commit 46369704d3f7ed9c26f0c3cc502914cbfcb58754 Author: maulanaww <129981489+maulanaww@users.noreply.github.com> Date: Mon Jul 22 11:55:45 2024 +0700 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/appInsightsSettings.xml b/.idea/appInsightsSettings.xml new file mode 100644 index 0000000..5f80e86 --- /dev/null +++ b/.idea/appInsightsSettings.xml @@ -0,0 +1,26 @@ + + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b589d56 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..b268ef3 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..574ce54 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..8978d23 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..5d79d74 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,48 @@ +plugins { + id 'com.android.application' + id 'com.google.gms.google-services' +} + +android { + namespace 'com.maulanawirawisesa.airsavvy' + compileSdk 34 + + defaultConfig { + applicationId "com.maulanawirawisesa.airsavvy" + minSdk 21 + targetSdk 34 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'com.google.android.material:material:1.12.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'com.google.firebase:firebase-database:21.0.0' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + implementation 'com.firebase:firebase-client-android:2.3.1' + implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5' + implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1' + implementation "androidx.room:room-runtime:2.4.2" + annotationProcessor "androidx.room:room-compiler:2.4.2" + implementation "androidx.room:room-ktx:2.4.2" + implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0' +} \ No newline at end of file diff --git a/app/google-services.json b/app/google-services.json new file mode 100644 index 0000000..d857d40 --- /dev/null +++ b/app/google-services.json @@ -0,0 +1,29 @@ +{ + "project_info": { + "project_number": "271516546506", + "project_id": "airsavvy-6e5e1", + "storage_bucket": "airsavvy-6e5e1.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:271516546506:android:adb0ea8441d5efc1cc4b33", + "android_client_info": { + "package_name": "com.maulanawirawisesa.airsavvy" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyDDmW_TPBKMVyrCKse2kI2Z4j-1ssUKAcc" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/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/app/src/androidTest/java/com/maulanawirawisesa/airsavvy/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/maulanawirawisesa/airsavvy/ExampleInstrumentedTest.java new file mode 100644 index 0000000..5b1c7e6 --- /dev/null +++ b/app/src/androidTest/java/com/maulanawirawisesa/airsavvy/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.maulanawirawisesa.airsavvy; + +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("com.maulanawirawisesa.airsavvy", appContext.getPackageName()); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..5f3bc3d --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/maulanawirawisesa/airsavvy/FireApp.java b/app/src/main/java/com/maulanawirawisesa/airsavvy/FireApp.java new file mode 100644 index 0000000..b11a56a --- /dev/null +++ b/app/src/main/java/com/maulanawirawisesa/airsavvy/FireApp.java @@ -0,0 +1,15 @@ +package com.maulanawirawisesa.airsavvy; + +import android.app.Application; + +import com.firebase.client.Firebase; + +public class FireApp extends Application { + + @Override + public void onCreate() { + super.onCreate(); + + Firebase.setAndroidContext(this); + } +} diff --git a/app/src/main/java/com/maulanawirawisesa/airsavvy/MainActivity.java b/app/src/main/java/com/maulanawirawisesa/airsavvy/MainActivity.java new file mode 100644 index 0000000..9cab02f --- /dev/null +++ b/app/src/main/java/com/maulanawirawisesa/airsavvy/MainActivity.java @@ -0,0 +1,14 @@ +package com.maulanawirawisesa.airsavvy; + +import androidx.appcompat.app.AppCompatActivity; + +import android.os.Bundle; + +public class MainActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/maulanawirawisesa/airsavvy/adapter/SensorDataAdapter.java b/app/src/main/java/com/maulanawirawisesa/airsavvy/adapter/SensorDataAdapter.java new file mode 100644 index 0000000..0d1e8cb --- /dev/null +++ b/app/src/main/java/com/maulanawirawisesa/airsavvy/adapter/SensorDataAdapter.java @@ -0,0 +1,62 @@ +package com.maulanawirawisesa.airsavvy.adapter; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.maulanawirawisesa.airsavvy.R; +import com.maulanawirawisesa.airsavvy.database.SensorData; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +public class SensorDataAdapter extends RecyclerView.Adapter { + + private List sensorDataList; + + public SensorDataAdapter(List sensorDataList) { + this.sensorDataList = sensorDataList; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_sensor_data, parent, false); + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + SensorData sensorData = sensorDataList.get(position); + holder.textViewSensorType.setText(sensorData.sensorType); + holder.textViewSensorValue.setText(String.valueOf(sensorData.value)); + + SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); + String formattedDate = sdf.format(new Date(sensorData.timestamp)); + holder.textViewTimestamp.setText(formattedDate); + } + + @Override + public int getItemCount() { + return sensorDataList.size(); + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + public TextView textViewSensorType; + public TextView textViewSensorValue; + public TextView textViewTimestamp; + + public ViewHolder(View itemView) { + super(itemView); + textViewSensorType = itemView.findViewById(R.id.textViewSensorType); + textViewSensorValue = itemView.findViewById(R.id.textViewSensorValue); + textViewTimestamp = itemView.findViewById(R.id.textViewTimestamp); + } + } +} + diff --git a/app/src/main/java/com/maulanawirawisesa/airsavvy/database/SensorData.java b/app/src/main/java/com/maulanawirawisesa/airsavvy/database/SensorData.java new file mode 100644 index 0000000..639da45 --- /dev/null +++ b/app/src/main/java/com/maulanawirawisesa/airsavvy/database/SensorData.java @@ -0,0 +1,24 @@ +package com.maulanawirawisesa.airsavvy.database; + +import androidx.room.ColumnInfo; +import androidx.room.Entity; +import androidx.room.PrimaryKey; + +@Entity(tableName = "sensor_data") +public class SensorData { + @PrimaryKey(autoGenerate = true) + public int id; + + @ColumnInfo(name = "sensor_type") + public String sensorType; + + @ColumnInfo(name = "value") + public float value; + + @ColumnInfo(name = "timestamp") + public long timestamp; // gunakan tipe data long untuk menyimpan timestamp + + public static float getValue(SensorData data) { + return data.value; + } +} diff --git a/app/src/main/java/com/maulanawirawisesa/airsavvy/database/SensorDataDao.java b/app/src/main/java/com/maulanawirawisesa/airsavvy/database/SensorDataDao.java new file mode 100644 index 0000000..8f2b1f2 --- /dev/null +++ b/app/src/main/java/com/maulanawirawisesa/airsavvy/database/SensorDataDao.java @@ -0,0 +1,35 @@ +package com.maulanawirawisesa.airsavvy.database; + +import androidx.room.Dao; +import androidx.room.Insert; +import androidx.room.Query; + +import java.util.List; + +@Dao +public interface SensorDataDao { + @Query("SELECT * FROM sensor_data") + List getAll(); + + @Insert + void insertAll(SensorData... sensorData); + + @Query("SELECT * FROM sensor_data WHERE timestamp >= :startOfDay AND timestamp <= :endOfDay") + List getDataForToday(long startOfDay, long endOfDay); + + @Query("SELECT AVG(value) FROM sensor_data WHERE sensor_type = :type AND timestamp >= :dateStart AND timestamp < :dateEnd") + float getAverageByTypeAndDate(String type, String dateStart, String dateEnd); + + @Query("SELECT * FROM sensor_data WHERE timestamp >= :startOfDay AND timestamp <= :endOfDay") + List getDataForTodayWithDate(long startOfDay, long endOfDay); + + @Query("SELECT * FROM sensor_data WHERE sensor_type = 'CO' AND timestamp >= :startOfDay AND timestamp <= :endOfDay") + List getCODataForToday(long startOfDay, long endOfDay); + + @Query("SELECT * FROM sensor_data WHERE sensor_type = 'CO2' AND timestamp >= :startOfDay AND timestamp <= :endOfDay") + List getCO2DataForToday(long startOfDay, long endOfDay); + + default List getDataForToday(long startOfDay, long endOfDay, String dateStr) { + return getDataForToday(startOfDay, endOfDay); + } +} diff --git a/app/src/main/java/com/maulanawirawisesa/airsavvy/database/SensorDatabase.java b/app/src/main/java/com/maulanawirawisesa/airsavvy/database/SensorDatabase.java new file mode 100644 index 0000000..d840723 --- /dev/null +++ b/app/src/main/java/com/maulanawirawisesa/airsavvy/database/SensorDatabase.java @@ -0,0 +1,9 @@ +package com.maulanawirawisesa.airsavvy.database; + +import androidx.room.Database; +import androidx.room.RoomDatabase; + +@Database(entities = {SensorData.class}, version = 1) +public abstract class SensorDatabase extends RoomDatabase { + public abstract SensorDataDao sensorDataDao(); +} diff --git a/app/src/main/java/com/maulanawirawisesa/airsavvy/helper/MqttHelper.java b/app/src/main/java/com/maulanawirawisesa/airsavvy/helper/MqttHelper.java new file mode 100644 index 0000000..eac40ae --- /dev/null +++ b/app/src/main/java/com/maulanawirawisesa/airsavvy/helper/MqttHelper.java @@ -0,0 +1,111 @@ +package com.maulanawirawisesa.airsavvy.helper; + +import android.content.Context; +import android.util.Log; +import org.eclipse.paho.android.service.MqttAndroidClient; +import org.eclipse.paho.client.mqttv3.IMqttActionListener; +import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; +import org.eclipse.paho.client.mqttv3.IMqttToken; +import org.eclipse.paho.client.mqttv3.MqttCallbackExtended; +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttConnectOptions; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttMessage; + +public class MqttHelper { + + private MqttAndroidClient mqttAndroidClient; + + final String serverUri = "tcp://192.168.0.106:1883"; + final String clientId = MqttClient.generateClientId(); + final String subscriptionTopic = "control"; + final String username = "airsavvy"; + final String password = "bismillah"; + + public MqttHelper(Context context) { + mqttAndroidClient = new MqttAndroidClient(context, serverUri, clientId); + mqttAndroidClient.setCallback(new MqttCallbackExtended() { + @Override + public void connectComplete(boolean reconnect, String serverURI) { + Log.d("Mqtt", "Connected to: " + serverURI); + } + + @Override + public void connectionLost(Throwable cause) { + Log.d("Mqtt", "Connection Lost"); + } + + @Override + public void messageArrived(String topic, MqttMessage message) throws Exception { + Log.d("Mqtt", "Message Arrived: " + topic + ": " + new String(message.getPayload())); + } + + @Override + public void deliveryComplete(IMqttDeliveryToken token) { + Log.d("Mqtt", "Delivery Complete"); + } + }); + + connect(); + } + + private void connect() { + MqttConnectOptions mqttConnectOptions = new MqttConnectOptions(); + mqttConnectOptions.setAutomaticReconnect(true); + mqttConnectOptions.setCleanSession(false); + mqttConnectOptions.setUserName(username); + mqttConnectOptions.setPassword(password.toCharArray()); + + try { + mqttAndroidClient.connect(mqttConnectOptions, null, new IMqttActionListener() { + @Override + public void onSuccess(IMqttToken asyncActionToken) { + Log.d("Mqtt", "Connected!"); + + subscribeToTopic(); + } + + @Override + public void onFailure(IMqttToken asyncActionToken, Throwable exception) { + Log.d("Mqtt", "Failed to connect to: " + serverUri); + } + }); + } catch (MqttException ex) { + ex.printStackTrace(); + } + } + + public void subscribeToTopic() { + try { + mqttAndroidClient.subscribe(subscriptionTopic, 0, null, new IMqttActionListener() { + @Override + public void onSuccess(IMqttToken asyncActionToken) { + Log.d("Mqtt", "Subscribed!"); + } + + @Override + public void onFailure(IMqttToken asyncActionToken, Throwable exception) { + Log.d("Mqtt", "Failed to subscribe"); + } + }); + } catch (MqttException ex) { + Log.e("Mqtt", "Exception whilst subscribing", ex); + } + } + + public void publishMessage(String message, String topic) { + try { + MqttMessage mqttMessage = new MqttMessage(); + mqttMessage.setPayload(message.getBytes()); + mqttAndroidClient.publish(topic, mqttMessage); + Log.d("Mqtt", "Message Published to " + topic); + } catch (MqttException e) { + Log.e("Mqtt", "Error Publishing: " + e.getMessage()); + e.printStackTrace(); + } + } + + public void setCallback(MqttCallbackExtended callback) { + mqttAndroidClient.setCallback(callback); + } +} diff --git a/app/src/main/java/com/maulanawirawisesa/airsavvy/ui/DashboardActivity.java b/app/src/main/java/com/maulanawirawisesa/airsavvy/ui/DashboardActivity.java new file mode 100644 index 0000000..d20d2c4 --- /dev/null +++ b/app/src/main/java/com/maulanawirawisesa/airsavvy/ui/DashboardActivity.java @@ -0,0 +1,533 @@ +package com.maulanawirawisesa.airsavvy.ui; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.SwitchCompat; +import androidx.room.Room; + +import android.content.Intent; +import android.os.Bundle; +import android.view.MotionEvent; +import android.view.View; +import android.widget.CompoundButton; +import android.widget.HorizontalScrollView; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.TextView; +import com.firebase.client.DataSnapshot; +import com.firebase.client.Firebase; +import com.firebase.client.FirebaseError; +import com.firebase.client.ValueEventListener; +import com.google.android.material.progressindicator.CircularProgressIndicator; +import com.google.android.material.progressindicator.LinearProgressIndicator; +import com.maulanawirawisesa.airsavvy.R; +import com.maulanawirawisesa.airsavvy.database.SensorData; +import com.maulanawirawisesa.airsavvy.database.SensorDatabase; +import com.maulanawirawisesa.airsavvy.helper.MqttHelper; + +import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; +import org.eclipse.paho.client.mqttv3.MqttCallbackExtended; +import org.eclipse.paho.client.mqttv3.MqttMessage; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +public class DashboardActivity extends AppCompatActivity { + + // inisialisasi textview nilai + private TextView indicatorValueCO2; + private TextView valueCO2; + private TextView informationCO2; + private TextView indicatorValueCO; + private TextView valueCO; + private TextView informationCO; + private TextView highIndicatorValueCO2; + private TextView timeHighKarbonDioksida; + private TextView highIndicatorValueCO; + private TextView timeHighKarbonMonoksida; + private CircularProgressIndicator indicatorCO2; + private CircularProgressIndicator indicatorCO; + private LinearProgressIndicator highIndicatorCO2; + private LinearProgressIndicator highIndicatorCO; + + // reference untuk firebase (koneksi server / host firebase) + private Firebase mRef1; + private Firebase mRef2; + private Firebase mRef3; + private Firebase mRef4; + private Firebase mRefMode; + private Firebase mRefRelay1; + private Firebase mRefRelay2; + private Firebase mRefRelay3; + private Firebase mRefRelay4; + + // inisiasi mqtt + MqttHelper mqttHelper; + private ImageButton statusButton; + private boolean isStatusTrue = false; + private boolean isScrollable = false; + private SwitchCompat switchFan1; + private SwitchCompat switchFan2; + private SwitchCompat switchFan3; + private SwitchCompat switchFan4; + private HorizontalScrollView scrollView; + + // Variabel untuk menyimpan nilai CO dan CO2 + private float sumCO = 0; + private float sumCO2 = 0; + private int countCO = 0; + private int countCO2 = 0; + + private ImageView history; + + // Database + private SensorDatabase db; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_dashboard); + + // navigasi ke page history + history = findViewById(R.id.history); + history.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // Menggunakan Intent untuk memulai HistoryActivity + Intent intent = new Intent(DashboardActivity.this, HistoryActivity.class); + startActivity(intent); + } + }); + + // Disable dan enable scroll dan fan + scrollView = findViewById(R.id.scrollView); + switchFan1 = findViewById(R.id.switchFan1); + switchFan2 = findViewById(R.id.switchFan2); + switchFan3 = findViewById(R.id.switchFan3); + switchFan4 = findViewById(R.id.switchFan4); + + // MQTT + mqttHelper = new MqttHelper(this); + statusButton = findViewById(R.id.statusButton); + + // baca komponen nilai (textview) + indicatorValueCO2 = (TextView) findViewById(R.id.indicatorValueCO2); + valueCO2 = (TextView) findViewById(R.id.valueCO2); + informationCO2 = (TextView) findViewById(R.id.informationCO2); + indicatorValueCO = (TextView) findViewById(R.id.indicatorValueCO); + valueCO = (TextView) findViewById(R.id.valueCO); + informationCO = (TextView) findViewById(R.id.informationCO); + indicatorCO2 = findViewById(R.id.indicatorCO2); + indicatorCO = findViewById(R.id.indicatorCO); + highIndicatorValueCO2 = findViewById(R.id.highIndicatorValueCO2); + timeHighKarbonDioksida = findViewById(R.id.timeHighKarbonDioksida); + highIndicatorValueCO = findViewById(R.id.highIndicatorValueCO); + timeHighKarbonMonoksida = findViewById(R.id.timeHighKarbonMonoksida); + highIndicatorCO2 = findViewById(R.id.highIndicatorCO2); + highIndicatorCO = findViewById(R.id.highIndicatorCO); + + // Inisialisasi database Room + db = Room.databaseBuilder(getApplicationContext(), + SensorDatabase.class, "sensor-db").build(); + + //buka koneksi ke host firebase + mRef1 = new Firebase("https://airsavvy-6e5e1-default-rtdb.firebaseio.com/CO2_ppm"); + mRef2 = new Firebase("https://airsavvy-6e5e1-default-rtdb.firebaseio.com/CO_ppm"); + mRef3 = new Firebase("https://airsavvy-6e5e1-default-rtdb.firebaseio.com/Kategori_CO"); + mRef4 = new Firebase("https://airsavvy-6e5e1-default-rtdb.firebaseio.com/Kategori_CO2"); + mRefMode = new Firebase("https://airsavvy-6e5e1-default-rtdb.firebaseio.com/Mode"); + mRefRelay1 = new Firebase("https://airsavvy-6e5e1-default-rtdb.firebaseio.com/Relay1"); + mRefRelay2 = new Firebase("https://airsavvy-6e5e1-default-rtdb.firebaseio.com/Relay2"); + mRefRelay3 = new Firebase("https://airsavvy-6e5e1-default-rtdb.firebaseio.com/Relay3"); + mRefRelay4 = new Firebase("https://airsavvy-6e5e1-default-rtdb.firebaseio.com/Relay4"); + + // proses realtime + mRef1.addValueEventListener(new ValueEventListener() { + @Override + public void onDataChange(DataSnapshot dataSnapshot) { + // Ambil nilai field1 + String CO2_ppm = dataSnapshot.getValue(String.class); + // Lakukan sesuatu dengan nilai yang Anda ambil + indicatorValueCO2.setText(CO2_ppm); + valueCO2.setText(CO2_ppm); + + // Set nilai progress bar + float CO2Value = Float.parseFloat(CO2_ppm); + int progress = (int) (CO2Value / 2000 * 100); + indicatorCO2.setProgressCompat(progress, true); + saveSensorData("CO2", CO2Value); + } + + @Override + public void onCancelled(FirebaseError firebaseError) { + // Handle kesalahan + } + }); + + mRef2.addValueEventListener(new ValueEventListener() { + @Override + public void onDataChange(DataSnapshot dataSnapshot) { + // Ambil nilai field2 + String CO_ppm = dataSnapshot.getValue(String.class); + // Lakukan sesuatu dengan nilai yang Anda ambil + indicatorValueCO.setText(CO_ppm); + valueCO.setText(CO_ppm); + + // Set nilai progress bar + float COValue = Float.parseFloat(CO_ppm); + int progress = (int) (COValue / 50 * 100); + indicatorCO.setProgressCompat(progress, true); + saveSensorData("CO", COValue); + } + + @Override + public void onCancelled(FirebaseError firebaseError) { + // Handle kesalahan + } + }); + + mRef3.addValueEventListener(new ValueEventListener() { + @Override + public void onDataChange(DataSnapshot dataSnapshot) { + // Ambil nilai field3 + String Kategori_CO = dataSnapshot.getValue(String.class); + // Lakukan sesuatu dengan nilai yang Anda ambil + informationCO.setText(Kategori_CO); + } + + @Override + public void onCancelled(FirebaseError firebaseError) { + // Handle kesalahan + } + }); + + mRef4.addValueEventListener(new ValueEventListener() { + @Override + public void onDataChange(DataSnapshot dataSnapshot) { + // Ambil nilai field4 + String Kategori_CO2 = dataSnapshot.getValue(String.class); + // Lakukan sesuatu dengan nilai yang Anda ambil + informationCO2.setText(Kategori_CO2); + } + + @Override + public void onCancelled(FirebaseError firebaseError) { + // Handle kesalahan + } + }); + + mRefMode.addValueEventListener(new ValueEventListener() { + @Override + public void onDataChange(DataSnapshot dataSnapshot) { + // Ambil nilai mode + int Mode = dataSnapshot.getValue(Integer.class); + if (Mode == 1) { + statusButton.setImageResource(R.drawable.manual); + // Mode 1: Enable scroll, enable switch fan + scrollView.setOnTouchListener(null); + switchFan1.setEnabled(true); + switchFan2.setEnabled(true); + switchFan3.setEnabled(true); + switchFan4.setEnabled(true); + mRefRelay1.addValueEventListener(new ValueEventListener() { + @Override + public void onDataChange(DataSnapshot dataSnapshot) { + // Ambil nilai mode + String Relay1 = dataSnapshot.getValue(String.class); + + // Update kondisi switch + if (Relay1 != null) { + if (Relay1.equals("ON")) { + switchFan1.setChecked(true); + } else if (Relay1.equals("OFF")) { + switchFan1.setChecked(false); + } + } + } + + @Override + public void onCancelled(FirebaseError firebaseError) { + // Handle possible errors. + } + }); + + mRefRelay2.addValueEventListener(new ValueEventListener() { + @Override + public void onDataChange(DataSnapshot dataSnapshot) { + // Ambil nilai mode + String Relay2 = dataSnapshot.getValue(String.class); + + // Update kondisi switch + if (Relay2 != null) { + if (Relay2.equals("ON")) { + switchFan2.setChecked(true); + } else if (Relay2.equals("OFF")) { + switchFan2.setChecked(false); + } + } + } + + @Override + public void onCancelled(FirebaseError firebaseError) { + // Handle possible errors. + } + }); + + mRefRelay3.addValueEventListener(new ValueEventListener() { + @Override + public void onDataChange(DataSnapshot dataSnapshot) { + // Ambil nilai mode + String Relay3 = dataSnapshot.getValue(String.class); + + // Update kondisi switch + if (Relay3 != null) { + if (Relay3.equals("ON")) { + switchFan3.setChecked(true); + } else if (Relay3.equals("OFF")) { + switchFan3.setChecked(false); + } + } + } + + @Override + public void onCancelled(FirebaseError firebaseError) { + // Handle possible errors. + } + }); + + mRefRelay4.addValueEventListener(new ValueEventListener() { + @Override + public void onDataChange(DataSnapshot dataSnapshot) { + // Ambil nilai mode + String Relay4 = dataSnapshot.getValue(String.class); + + // Update kondisi switch + if (Relay4 != null) { + if (Relay4.equals("ON")) { + switchFan4.setChecked(true); + } else if (Relay4.equals("OFF")) { + switchFan4.setChecked(false); + } + } + } + + @Override + public void onCancelled(FirebaseError firebaseError) { + // Handle possible errors. + } + }); + } else { + // Mode 0: Disable scroll, disable switch fan + statusButton.setImageResource(R.drawable.auto); + scrollView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return true; + } + }); + switchFan1.setEnabled(false); + switchFan2.setEnabled(false); + switchFan3.setEnabled(false); + switchFan4.setEnabled(false); + switchFan1.setChecked(false); + switchFan2.setChecked(false); + switchFan3.setChecked(false); + switchFan4.setChecked(false); + } + } + + @Override + public void onCancelled(FirebaseError firebaseError) { + // Handle possible errors. + } + }); + + // Ambil tanggal hari ini + Calendar cal = Calendar.getInstance(); + Date today = cal.getTime(); + + // Ambil tanggal 1 hari yang lalu + cal.add(Calendar.DATE, -1); + Date yesterday = cal.getTime(); + + // Format tanggal untuk query ke database + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + + // Ambil data dari database untuk CO dan CO2 dari 1 hari yang lalu + new Thread(() -> { + long startOfDay = getStartOfDay(yesterday); + long endOfDay = getEndOfDay(yesterday); + + List sensorDataCO = db.sensorDataDao().getCODataForToday(startOfDay, endOfDay); + List sensorDataCO2 = db.sensorDataDao().getCO2DataForToday(startOfDay, endOfDay); + + int totalCO = 0; + for (SensorData data : sensorDataCO) { + totalCO += data.value; + } + int avgCO = sensorDataCO.size() > 0 ? totalCO / sensorDataCO.size() : 0; + + int totalCO2 = 0; + for (SensorData data : sensorDataCO2) { + totalCO2 += data.value; + } + int avgCO2 = sensorDataCO2.size() > 0 ? totalCO2 / sensorDataCO2.size() : 0; + + // Update UI dengan menggunakan runOnUiThread + runOnUiThread(() -> { + highIndicatorValueCO.setText(String.valueOf(avgCO)); + highIndicatorValueCO2.setText(String.valueOf(avgCO2)); + timeHighKarbonDioksida.setText(formatDate(yesterday)); + timeHighKarbonMonoksida.setText(formatDate(yesterday)); + + // Set nilai rata-rata ke ProgressBar + int progressCO = (int) (avgCO / 50f * 100); + int progressCO2 = (int) (avgCO2 / 2000f * 100); + highIndicatorCO.setProgressCompat(progressCO, true); + highIndicatorCO2.setProgressCompat(progressCO2, true); + }); + }).start(); + + + mqttHelper.setCallback(new MqttCallbackExtended() { + @Override + public void connectComplete(boolean reconnect, String serverURI) { + mqttHelper.subscribeToTopic(); + } + + @Override + public void connectionLost(Throwable cause) { + // Handle lost connection + } + + @Override + public void messageArrived(String topic, MqttMessage message) throws Exception { + String status = new String(message.getPayload()); + isStatusTrue = "1".equals(status); + updateButton(); + } + + @Override + public void deliveryComplete(IMqttDeliveryToken token) { + // Handle completed delivery + } + }); + + statusButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + toggleStatus(); + } + }); + + switchFan1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + mqttHelper.publishMessage(isChecked ? "0" : "1", "control/relay1"); + } + }); + + switchFan2.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + mqttHelper.publishMessage(isChecked ? "0" : "1", "control/relay2"); + } + }); + + switchFan3.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + mqttHelper.publishMessage(isChecked ? "0" : "1", "control/relay3"); + } + }); + + switchFan4.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + mqttHelper.publishMessage(isChecked ? "0" : "1", "control/relay4"); + } + }); + + scrollView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + // Mengembalikan nilai true agar scrollView dapat di-scroll + boolean isScrolling = !isScrollable; + switchFan1.setEnabled(!isScrolling); + switchFan2.setEnabled(!isScrolling); + switchFan3.setEnabled(!isScrolling); + switchFan4.setEnabled(!isScrolling); + return isScrolling; + } + }); + + } + + private void toggleStatus() { + isStatusTrue = !isStatusTrue; + mqttHelper.publishMessage(isStatusTrue ? "1" : "0", "control/mode"); + updateButton(); + + // Mengatur scrollability berdasarkan status tombol + isScrollable = isStatusTrue; + + // Mengatur disable/enable pada switchFan1, switchFan2, switchFan3, dan switchFan4 + switchFan1.setEnabled(!isScrollable); + switchFan2.setEnabled(!isScrollable); + switchFan3.setEnabled(!isScrollable); + switchFan4.setEnabled(!isScrollable); + } + + private void updateButton() { + if (isStatusTrue) { + statusButton.setImageResource(R.drawable.manual); + } else { + statusButton.setImageResource(R.drawable.auto); + } + } + + private void saveSensorData(String sensorType, float value) { + // Buat objek SensorData + SensorData sensorData = new SensorData(); + sensorData.sensorType = sensorType; + sensorData.value = value; + sensorData.timestamp = System.currentTimeMillis(); // set timestamp saat data disimpan + + // Simpan data ke database menggunakan thread baru + new Thread(() -> db.sensorDataDao().insertAll(sensorData)).start(); + } + + private long getStartOfDay(Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + return cal.getTimeInMillis(); + } + + private long getEndOfDay(Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.set(Calendar.HOUR_OF_DAY, 23); + cal.set(Calendar.MINUTE, 59); + cal.set(Calendar.SECOND, 59); + cal.set(Calendar.MILLISECOND, 999); + return cal.getTimeInMillis(); + } + + private float calculateAverage(List sensorDataList) { + float sum = 0; + for (SensorData data : sensorDataList) { + sum += data.value; // Menggunakan atribut 'value' dari objek SensorData + } + return sum / sensorDataList.size(); + } + + private String formatDate(Date date) { + SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); + return sdf.format(date); + } +} diff --git a/app/src/main/java/com/maulanawirawisesa/airsavvy/ui/HistoryActivity.java b/app/src/main/java/com/maulanawirawisesa/airsavvy/ui/HistoryActivity.java new file mode 100644 index 0000000..f638afd --- /dev/null +++ b/app/src/main/java/com/maulanawirawisesa/airsavvy/ui/HistoryActivity.java @@ -0,0 +1,276 @@ +package com.maulanawirawisesa.airsavvy.ui; + +import android.content.Context; +import android.content.Intent; +import android.graphics.Color; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.Toast; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.room.Room; +import com.github.mikephil.charting.charts.LineChart; +import com.github.mikephil.charting.components.Legend; +import com.github.mikephil.charting.components.XAxis; +import com.github.mikephil.charting.components.YAxis; +import com.github.mikephil.charting.data.Entry; +import com.github.mikephil.charting.data.LineData; +import com.github.mikephil.charting.data.LineDataSet; +import com.github.mikephil.charting.formatter.ValueFormatter; +import com.github.mikephil.charting.interfaces.datasets.ILineDataSet; +import com.maulanawirawisesa.airsavvy.R; +import com.maulanawirawisesa.airsavvy.adapter.SensorDataAdapter; +import com.maulanawirawisesa.airsavvy.database.SensorData; +import com.maulanawirawisesa.airsavvy.database.SensorDatabase; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +public class HistoryActivity extends AppCompatActivity { + + private ImageView back; + private RecyclerView recyclerViewToday; + private RecyclerView recyclerViewYesterday; + private SensorDataAdapter sensorDataAdapterToday; + private SensorDataAdapter sensorDataAdapterYesterday; + private LineChart lineChartToday; + private LineChart lineChartYesterday; + private SensorDatabase db; + private Handler handler; + private Runnable updateRunnable; + private static final int UPDATE_INTERVAL = 5000; // Interval pembaruan dalam milidetik (misalnya 5000 = 5 detik) + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_history); + + recyclerViewToday = findViewById(R.id.recyclerViewToday); + recyclerViewToday.setLayoutManager(new LinearLayoutManager(this)); + recyclerViewYesterday = findViewById(R.id.recyclerViewYesterday); + recyclerViewYesterday.setLayoutManager(new LinearLayoutManager(this)); + lineChartToday = findViewById(R.id.lineChartToday); + lineChartYesterday = findViewById(R.id.lineChartYesterday); + + // Inisialisasi database Room + db = Room.databaseBuilder(getApplicationContext(), + SensorDatabase.class, "sensor-db").build(); + + handler = new Handler(Looper.getMainLooper()); + updateRunnable = new Runnable() { + @Override + public void run() { + updateDataAndCharts(); + handler.postDelayed(this, UPDATE_INTERVAL); + } + }; + + // Memulai pembaruan data secara periodik + handler.post(updateRunnable); + + // navigasi ke page history + back = findViewById(R.id.back); + back.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // Menggunakan Intent untuk memulai HistoryActivity + Intent intent = new Intent(HistoryActivity.this, DashboardActivity.class); + startActivity(intent); + // Hentikan pembaruan periodik saat meninggalkan halaman + handler.removeCallbacks(updateRunnable); + } + }); + } + + private void updateDataAndCharts() { + // Mendapatkan timestamp awal hari ini + Calendar startCalendar = Calendar.getInstance(); + startCalendar.set(Calendar.HOUR_OF_DAY, 0); + startCalendar.set(Calendar.MINUTE, 0); + startCalendar.set(Calendar.SECOND, 0); + long startOfDay = startCalendar.getTimeInMillis(); + + // Mendapatkan timestamp akhir hari ini + Calendar endCalendar = Calendar.getInstance(); + endCalendar.set(Calendar.HOUR_OF_DAY, 23); + endCalendar.set(Calendar.MINUTE, 59); + endCalendar.set(Calendar.SECOND, 59); + long endOfDay = endCalendar.getTimeInMillis(); + + // Format timestamp menjadi jam, menit, dan detik + SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); + + // ValueFormatter untuk mengubah tampilan timestamp menjadi jam, menit, dan detik + ValueFormatter timeFormatter = new ValueFormatter() { + @Override + public String getFormattedValue(float value) { + return sdf.format(new Date((long) value)); + } + }; + + // Ambil dan perbarui data untuk hari ini + new Thread(() -> { + List sensorDataListToday = db.sensorDataDao().getDataForToday(startOfDay, endOfDay); + runOnUiThread(() -> { + sensorDataAdapterToday = new SensorDataAdapter(sensorDataListToday); + recyclerViewToday.setAdapter(sensorDataAdapterToday); + }); + + List entriesCO = new ArrayList<>(); + List entriesCO2 = new ArrayList<>(); + for (SensorData sensorData : sensorDataListToday) { + if (sensorData.sensorType.equals("CO")) { + entriesCO.add(new Entry(sensorData.timestamp, sensorData.value)); + } else if (sensorData.sensorType.equals("CO2")) { + entriesCO2.add(new Entry(sensorData.timestamp, sensorData.value)); + } + } + LineDataSet dataSetCO = new LineDataSet(entriesCO, "CO"); + dataSetCO.setColor(Color.RED); + dataSetCO.setLineWidth(2f); + dataSetCO.setCircleColor(Color.RED); + dataSetCO.setCircleRadius(4f); + dataSetCO.setDrawValues(false); + + LineDataSet dataSetCO2 = new LineDataSet(entriesCO2, "CO2"); + dataSetCO2.setColor(Color.BLUE); + dataSetCO2.setLineWidth(2f); + dataSetCO2.setCircleColor(Color.BLUE); + dataSetCO2.setCircleRadius(4f); + dataSetCO2.setDrawValues(false); + + List dataSets = new ArrayList<>(); + dataSets.add(dataSetCO); + dataSets.add(dataSetCO2); + + LineData lineData = new LineData(dataSets); + + runOnUiThread(() -> { + lineChartToday.setData(lineData); + lineChartToday.getDescription().setText("Hari Ini"); + lineChartToday.getDescription().setTextSize(12f); + lineChartToday.getDescription().setTextColor(Color.BLACK); + + Legend legend = lineChartToday.getLegend(); + legend.setForm(Legend.LegendForm.LINE); + legend.setTextSize(12f); + legend.setTextColor(Color.BLACK); + + XAxis xAxis = lineChartToday.getXAxis(); + xAxis.setPosition(XAxis.XAxisPosition.BOTTOM); + xAxis.setTextSize(10f); + xAxis.setTextColor(Color.BLACK); + xAxis.setDrawGridLines(true); + xAxis.setAvoidFirstLastClipping(true); + xAxis.setValueFormatter(timeFormatter); // Mengatur format label sumbu X + + YAxis leftAxis = lineChartToday.getAxisLeft(); + leftAxis.setTextSize(10f); + leftAxis.setTextColor(Color.BLACK); + leftAxis.setDrawGridLines(true); + + YAxis rightAxis = lineChartToday.getAxisRight(); + rightAxis.setEnabled(false); + + lineChartToday.animateX(1500); + lineChartToday.animateY(1500); + lineChartToday.invalidate(); // refresh chart + }); + }).start(); + + // Ambil dan perbarui data untuk kemarin + new Thread(() -> { + long startOfYesterday = startOfDay - (24 * 60 * 60 * 1000); + long endOfYesterday = endOfDay - (24 * 60 * 60 * 1000); + List sensorDataListYesterday = db.sensorDataDao().getDataForToday(startOfYesterday, endOfYesterday); + runOnUiThread(() -> { + sensorDataAdapterYesterday = new SensorDataAdapter(sensorDataListYesterday); + recyclerViewYesterday.setAdapter(sensorDataAdapterYesterday); + }); + + List entriesCO = new ArrayList<>(); + List entriesCO2 = new ArrayList<>(); + for (SensorData sensorData : sensorDataListYesterday) { + if (sensorData.sensorType.equals("CO")) { + entriesCO.add(new Entry(sensorData.timestamp, sensorData.value)); + } else if (sensorData.sensorType.equals("CO2")) { + entriesCO2.add(new Entry(sensorData.timestamp, sensorData.value)); + } + } + LineDataSet dataSetCO = new LineDataSet(entriesCO, "CO"); + dataSetCO.setColor(Color.RED); + dataSetCO.setLineWidth(2f); + dataSetCO.setCircleColor(Color.RED); + dataSetCO.setCircleRadius(4f); + dataSetCO.setDrawValues(false); + + LineDataSet dataSetCO2 = new LineDataSet(entriesCO2, "CO2"); + dataSetCO2.setColor(Color.BLUE); + dataSetCO2.setLineWidth(2f); + dataSetCO2.setCircleColor(Color.BLUE); + dataSetCO2.setCircleRadius(4f); + dataSetCO2.setDrawValues(false); + + List dataSets = new ArrayList<>(); + dataSets.add(dataSetCO); + dataSets.add(dataSetCO2); + + LineData lineData = new LineData(dataSets); + + runOnUiThread(() -> { + lineChartYesterday.setData(lineData); + lineChartYesterday.getDescription().setText("Kemarin"); + lineChartYesterday.getDescription().setTextSize(12f); + lineChartYesterday.getDescription().setTextColor(Color.BLACK); + + Legend legend = lineChartYesterday.getLegend(); + legend.setForm(Legend.LegendForm.LINE); + legend.setTextSize(12f); + legend.setTextColor(Color.BLACK); + + XAxis xAxis = lineChartYesterday.getXAxis(); + xAxis.setPosition(XAxis.XAxisPosition.BOTTOM); + xAxis.setTextSize(10f); + xAxis.setTextColor(Color.BLACK); + xAxis.setDrawGridLines(true); + xAxis.setAvoidFirstLastClipping(true); + xAxis.setValueFormatter(timeFormatter); // Mengatur format label sumbu X + + YAxis leftAxis = lineChartYesterday.getAxisLeft(); + leftAxis.setTextSize(10f); + leftAxis.setTextColor(Color.BLACK); + leftAxis.setDrawGridLines(true); + + YAxis rightAxis = lineChartYesterday.getAxisRight(); + rightAxis.setEnabled(false); + + lineChartYesterday.animateX(1500); + lineChartYesterday.animateY(1500); + lineChartYesterday.invalidate(); // refresh chart + }); + }).start(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + // Hentikan pembaruan periodik saat activity dihancurkan + handler.removeCallbacks(updateRunnable); + } +} diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/auto.xml b/app/src/main/res/drawable/auto.xml new file mode 100644 index 0000000..ce922ed --- /dev/null +++ b/app/src/main/res/drawable/auto.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/drawable/back.xml b/app/src/main/res/drawable/back.xml new file mode 100644 index 0000000..9acfe27 --- /dev/null +++ b/app/src/main/res/drawable/back.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/background.png b/app/src/main/res/drawable/background.png new file mode 100644 index 0000000..e9f03cb Binary files /dev/null and b/app/src/main/res/drawable/background.png differ diff --git a/app/src/main/res/drawable/bg_button_yellow.xml b/app/src/main/res/drawable/bg_button_yellow.xml new file mode 100644 index 0000000..75c7e0c --- /dev/null +++ b/app/src/main/res/drawable/bg_button_yellow.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/blue_box.xml b/app/src/main/res/drawable/blue_box.xml new file mode 100644 index 0000000..7f434d6 --- /dev/null +++ b/app/src/main/res/drawable/blue_box.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/control_box.xml b/app/src/main/res/drawable/control_box.xml new file mode 100644 index 0000000..3c674e3 --- /dev/null +++ b/app/src/main/res/drawable/control_box.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/fan.xml b/app/src/main/res/drawable/fan.xml new file mode 100644 index 0000000..4d80708 --- /dev/null +++ b/app/src/main/res/drawable/fan.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/history.xml b/app/src/main/res/drawable/history.xml new file mode 100644 index 0000000..44070c9 --- /dev/null +++ b/app/src/main/res/drawable/history.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/logo.png b/app/src/main/res/drawable/logo.png new file mode 100644 index 0000000..b3fe729 Binary files /dev/null and b/app/src/main/res/drawable/logo.png differ diff --git a/app/src/main/res/drawable/manual.xml b/app/src/main/res/drawable/manual.xml new file mode 100644 index 0000000..aafe14b --- /dev/null +++ b/app/src/main/res/drawable/manual.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/drawable/menu.xml b/app/src/main/res/drawable/menu.xml new file mode 100644 index 0000000..fa10835 --- /dev/null +++ b/app/src/main/res/drawable/menu.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable/profile.jpeg b/app/src/main/res/drawable/profile.jpeg new file mode 100644 index 0000000..b72492a Binary files /dev/null and b/app/src/main/res/drawable/profile.jpeg differ diff --git a/app/src/main/res/drawable/red_box.xml b/app/src/main/res/drawable/red_box.xml new file mode 100644 index 0000000..37654ff --- /dev/null +++ b/app/src/main/res/drawable/red_box.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shadow.png b/app/src/main/res/drawable/shadow.png new file mode 100644 index 0000000..aefea80 Binary files /dev/null and b/app/src/main/res/drawable/shadow.png differ diff --git a/app/src/main/res/drawable/shadow1.png b/app/src/main/res/drawable/shadow1.png new file mode 100644 index 0000000..6dd0590 Binary files /dev/null and b/app/src/main/res/drawable/shadow1.png differ diff --git a/app/src/main/res/drawable/shadow2.png b/app/src/main/res/drawable/shadow2.png new file mode 100644 index 0000000..413c3bf Binary files /dev/null and b/app/src/main/res/drawable/shadow2.png differ diff --git a/app/src/main/res/drawable/shadow3.png b/app/src/main/res/drawable/shadow3.png new file mode 100644 index 0000000..3e1b8a9 Binary files /dev/null and b/app/src/main/res/drawable/shadow3.png differ diff --git a/app/src/main/res/drawable/thumb.xml b/app/src/main/res/drawable/thumb.xml new file mode 100644 index 0000000..e552860 --- /dev/null +++ b/app/src/main/res/drawable/thumb.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/track.xml b/app/src/main/res/drawable/track.xml new file mode 100644 index 0000000..a082b21 --- /dev/null +++ b/app/src/main/res/drawable/track.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/yellow_box.xml b/app/src/main/res/drawable/yellow_box.xml new file mode 100644 index 0000000..7b4b859 --- /dev/null +++ b/app/src/main/res/drawable/yellow_box.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/font/quicksand.xml b/app/src/main/res/font/quicksand.xml new file mode 100644 index 0000000..982b40a --- /dev/null +++ b/app/src/main/res/font/quicksand.xml @@ -0,0 +1,7 @@ + + + diff --git a/app/src/main/res/font/quicksand_bold.xml b/app/src/main/res/font/quicksand_bold.xml new file mode 100644 index 0000000..a4b6e66 --- /dev/null +++ b/app/src/main/res/font/quicksand_bold.xml @@ -0,0 +1,7 @@ + + + diff --git a/app/src/main/res/font/quicksand_light.xml b/app/src/main/res/font/quicksand_light.xml new file mode 100644 index 0000000..2587c46 --- /dev/null +++ b/app/src/main/res/font/quicksand_light.xml @@ -0,0 +1,7 @@ + + + diff --git a/app/src/main/res/font/quicksand_medium.xml b/app/src/main/res/font/quicksand_medium.xml new file mode 100644 index 0000000..2d98b27 --- /dev/null +++ b/app/src/main/res/font/quicksand_medium.xml @@ -0,0 +1,7 @@ + + + diff --git a/app/src/main/res/layout/activity_dashboard.xml b/app/src/main/res/layout/activity_dashboard.xml new file mode 100644 index 0000000..40051c9 --- /dev/null +++ b/app/src/main/res/layout/activity_dashboard.xml @@ -0,0 +1,812 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_history.xml b/app/src/main/res/layout/activity_history.xml new file mode 100644 index 0000000..ccd76ac --- /dev/null +++ b/app/src/main/res/layout/activity_history.xml @@ -0,0 +1,249 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..17eab17 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_sensor_data.xml b/app/src/main/res/layout/item_sensor_data.xml new file mode 100644 index 0000000..1a8f9ed --- /dev/null +++ b/app/src/main/res/layout/item_sensor_data.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml new file mode 100644 index 0000000..e29738f --- /dev/null +++ b/app/src/main/res/values-night/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..eed2c04 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,20 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + #FFF4FCFF + #FFF66955 + #FFA0A5FF + #FFF5CD54 + #FFFE7F6D + #FFFFDF7C + #FFBCBFFF + #FF8C8C8C + #FFCDCDCD + #FFF4FCFF + \ No newline at end of file diff --git a/app/src/main/res/values/custom_image_style.xml b/app/src/main/res/values/custom_image_style.xml new file mode 100644 index 0000000..8e1ed02 --- /dev/null +++ b/app/src/main/res/values/custom_image_style.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/font_certs.xml b/app/src/main/res/values/font_certs.xml new file mode 100644 index 0000000..d2226ac --- /dev/null +++ b/app/src/main/res/values/font_certs.xml @@ -0,0 +1,17 @@ + + + + @array/com_google_android_gms_fonts_certs_dev + @array/com_google_android_gms_fonts_certs_prod + + + + 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 + + + diff --git a/app/src/main/res/values/preloaded_fonts.xml b/app/src/main/res/values/preloaded_fonts.xml new file mode 100644 index 0000000..8d8c441 --- /dev/null +++ b/app/src/main/res/values/preloaded_fonts.xml @@ -0,0 +1,9 @@ + + + + @font/quicksand + @font/quicksand_bold + @font/quicksand_light + @font/quicksand_medium + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..b9e9727 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,24 @@ + + AirSavvy + Hi! Maulana + 2000 + Karbon Dioksida + PPM + Kurang Baik + 20 + Karbon Monoksida + 08 : 17 : 56 + 10 : 03 : 29 + Control + Fan 1 + Fan 2 + Fan 3 + Fan 4 + Status Button + Today + Yesterday + Jenis + Nilai + Waktu + History Report + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..8b4618f --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 0000000..fa0f996 --- /dev/null +++ b/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 0000000..9ee9997 --- /dev/null +++ b/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/test/java/com/maulanawirawisesa/airsavvy/ExampleUnitTest.java b/app/src/test/java/com/maulanawirawisesa/airsavvy/ExampleUnitTest.java new file mode 100644 index 0000000..e42d392 --- /dev/null +++ b/app/src/test/java/com/maulanawirawisesa/airsavvy/ExampleUnitTest.java @@ -0,0 +1,17 @@ +package com.maulanawirawisesa.airsavvy; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..5568b8c --- /dev/null +++ b/build.gradle @@ -0,0 +1,9 @@ +buildscript { + dependencies { + classpath 'com.google.gms:google-services:4.4.1' + } +}// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + id 'com.android.application' version '7.3.1' apply false + id 'com.android.library' version '7.3.1' apply false +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..2eab451 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,23 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +android.enableJetifier=true +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true +android.suppressUnsupportedCompileSdk=34 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e708b1c Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..5801b78 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Thu May 16 10:27:10 ICT 2024 +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..4f906e0 --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..03e2e06 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,27 @@ +pluginManagement { + repositories { + maven{ + url "https://repo.eclipse.org/content/repositories/paho-snapshots/" + } + gradlePluginPortal() + google() + jcenter() + mavenCentral() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + maven{ + url "https://repo.eclipse.org/content/repositories/paho-snapshots/" + } + maven{ + url 'https://jitpack.io' + } + google() + jcenter() + mavenCentral() + } +} +rootProject.name = "AirSavvy" +include ':app'