From 13f8437f290a4e2f07b8dc61f2aa1aee6d402143 Mon Sep 17 00:00:00 2001 From: Mondei1 Date: Fri, 23 Oct 2020 00:39:36 +0200 Subject: [PATCH] Livebeat is now able to send, store and show beats --- android/app/build.gradle | 5 +- android/app/src/main/AndroidManifest.xml | 12 +- .../de/nicolasklier/livebeat/FirstFragment.kt | 31 - .../de/nicolasklier/livebeat/MainActivity.kt | 204 +++- .../java/de/nicolasklier/livebeat/Models.kt | 26 + .../nicolasklier/livebeat/SecondFragment.kt | 31 - .../nicolasklier/livebeat/TrackerService.java | 96 -- .../nicolasklier/livebeat/TrackerService.kt | 143 +++ .../res/drawable/round_clear_white_18dp.png | Bin 0 -> 221 bytes .../app/src/main/res/layout/activity_main.xml | 123 ++- .../app/src/main/res/layout/content_main.xml | 19 - .../src/main/res/layout/fragment_first.xml | 28 - .../src/main/res/layout/fragment_second.xml | 27 - .../app/src/main/res/navigation/nav_graph.xml | 28 - .../app/src/main/res/values-night/themes.xml | 16 - android/app/src/main/res/values/colors.xml | 10 +- android/app/src/main/res/values/themes.xml | 15 +- backend/app.ts | 19 +- backend/endpoints/beat.ts | 30 + backend/endpoints/phone.ts | 63 ++ backend/endpoints/user.ts | 28 +- backend/lib/rabbit.ts | 37 +- backend/lib/request.ts | 6 + .../beat.interface.ts} | 6 +- backend/models/beat/beat.model..ts | 6 + backend/models/beat/beat.schema.ts | 16 + backend/models/phone/phone.interface.ts | 1 + backend/models/phone/phone.schema.ts | 5 +- backend/models/track/track.model.ts | 6 - backend/models/track/track.schema.ts | 16 - backend/package-lock.json | 18 + backend/package.json | 4 +- frontend/angular.json | 4 +- frontend/package-lock.json | 991 ++++++++++++++++-- frontend/package.json | 4 + frontend/src/app/api.service.spec.ts | 16 + frontend/src/app/api.service.ts | 62 ++ frontend/src/app/app-routing.module.ts | 19 +- frontend/src/app/app.component.html | 15 +- frontend/src/app/app.component.scss | 10 + frontend/src/app/app.component.ts | 7 +- frontend/src/app/app.module.ts | 12 +- .../app/dashboard/dashboard.component.html | 13 + .../app/dashboard/dashboard.component.scss | 8 + .../app/dashboard/dashboard.component.spec.ts | 25 + .../src/app/dashboard/dashboard.component.ts | 32 + frontend/src/app/login/login.component.html | 16 + frontend/src/app/login/login.component.scss | 13 + .../src/app/login/login.component.spec.ts | 25 + frontend/src/app/login/login.component.ts | 31 + frontend/src/polyfills.ts | 1 + frontend/src/styles.scss | 11 +- 52 files changed, 1948 insertions(+), 442 deletions(-) delete mode 100644 android/app/src/main/java/de/nicolasklier/livebeat/FirstFragment.kt create mode 100644 android/app/src/main/java/de/nicolasklier/livebeat/Models.kt delete mode 100644 android/app/src/main/java/de/nicolasklier/livebeat/SecondFragment.kt delete mode 100644 android/app/src/main/java/de/nicolasklier/livebeat/TrackerService.java create mode 100644 android/app/src/main/java/de/nicolasklier/livebeat/TrackerService.kt create mode 100644 android/app/src/main/res/drawable/round_clear_white_18dp.png delete mode 100644 android/app/src/main/res/layout/content_main.xml delete mode 100644 android/app/src/main/res/layout/fragment_first.xml delete mode 100644 android/app/src/main/res/layout/fragment_second.xml delete mode 100644 android/app/src/main/res/navigation/nav_graph.xml delete mode 100644 android/app/src/main/res/values-night/themes.xml create mode 100644 backend/endpoints/beat.ts create mode 100644 backend/endpoints/phone.ts create mode 100644 backend/lib/request.ts rename backend/models/{track/track.interface.ts => beat/beat.interface.ts} (65%) create mode 100644 backend/models/beat/beat.model..ts create mode 100644 backend/models/beat/beat.schema.ts delete mode 100644 backend/models/track/track.model.ts delete mode 100644 backend/models/track/track.schema.ts create mode 100644 frontend/src/app/api.service.spec.ts create mode 100644 frontend/src/app/api.service.ts create mode 100644 frontend/src/app/dashboard/dashboard.component.html create mode 100644 frontend/src/app/dashboard/dashboard.component.scss create mode 100644 frontend/src/app/dashboard/dashboard.component.spec.ts create mode 100644 frontend/src/app/dashboard/dashboard.component.ts create mode 100644 frontend/src/app/login/login.component.html create mode 100644 frontend/src/app/login/login.component.scss create mode 100644 frontend/src/app/login/login.component.spec.ts create mode 100644 frontend/src/app/login/login.component.ts diff --git a/android/app/build.gradle b/android/app/build.gradle index fa4d776..817bc89 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -35,13 +35,16 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation 'androidx.core:core-ktx:1.2.0' + implementation 'androidx.core:core-ktx:1.3.2' implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'com.google.android.material:material:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.navigation:navigation-fragment-ktx:2.2.2' implementation 'androidx.navigation:navigation-ui-ktx:2.2.2' + implementation 'com.squareup.moshi:moshi:1.11.0' + implementation 'com.squareup.moshi:moshi-kotlin:1.11.0' implementation 'com.rabbitmq:amqp-client:5.9.0' + implementation "com.squareup.okhttp3:okhttp:4.9.0" testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 61b823e..471906a 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,9 +1,16 @@ - - + + + + + + (R.id.button_first).setOnClickListener { - findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment) - } - } -} \ No newline at end of file diff --git a/android/app/src/main/java/de/nicolasklier/livebeat/MainActivity.kt b/android/app/src/main/java/de/nicolasklier/livebeat/MainActivity.kt index 7d1a97d..0c77260 100644 --- a/android/app/src/main/java/de/nicolasklier/livebeat/MainActivity.kt +++ b/android/app/src/main/java/de/nicolasklier/livebeat/MainActivity.kt @@ -1,24 +1,202 @@ package de.nicolasklier.livebeat +import android.Manifest +import android.annotation.SuppressLint +import android.content.BroadcastReceiver +import android.content.Context import android.content.Intent +import android.content.IntentFilter +import android.content.pm.PackageManager +import android.graphics.Color +import android.os.Build import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.provider.Settings +import android.util.Log import android.view.Menu import android.view.MenuItem +import android.view.View +import android.widget.Button +import android.widget.TextView import androidx.appcompat.app.AppCompatActivity +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat import com.google.android.material.floatingactionbutton.FloatingActionButton import com.google.android.material.snackbar.Snackbar +import com.squareup.moshi.Moshi +import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.RequestBody.Companion.toRequestBody +import java.util.logging.Logger +@Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS") class MainActivity : AppCompatActivity() { + companion object { + @JvmStatic val API_URL = "http://192.168.178.26:8040" + var TOKEN = "" + } + + private var broadcastReceiver: BroadcastReceiver? = null + + @SuppressLint("HardwareIds") + fun checkIfPhoneIsRegistered() { + if (TOKEN == "") return; + Thread(Runnable { + val androidId = Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID) + val client = OkHttpClient() + val req = Request.Builder() + .url("$API_URL/phone/$androidId") + .get() + .build() + val response = client.newCall(req).execute() + + if (response.code != 200) { + Snackbar.make(findViewById(R.id.fab), "Device isn't registered yet.", Snackbar.LENGTH_SHORT) + .setBackgroundTint(Color.YELLOW) + .setTextColor(Color.BLACK) + .show() + + // Register device + val phone = Phone( + androidId, + Build.MODEL, + Build.PRODUCT, + Build.VERSION.RELEASE, + System.getProperty("os.arch") + ) + val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build() + val phoneToJson = moshi.adapter(Phone::class.java) + val json = phoneToJson.toJson(phone) + + val createPhone = Request.Builder() + .url("$API_URL/phone") + .post( + (json).toRequestBody() + ) + .header("Content-Type", "application/json") + .header("token", TOKEN) + .build() + client.newCall(createPhone).execute() + } + }).start() + } + override fun onCreate(savedInstanceState: Bundle?) { + checkPerms() + super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setSupportActionBar(findViewById(R.id.toolbar)) startService(Intent(this, TrackerService::class.java)) + // Check authorization + val backendChecks = Thread(Runnable { + val username = findViewById(R.id.username).text + val password = findViewById(R.id.password).text + val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build() + val jsonToLogin = moshi.adapter(Login::class.java) + + val client = OkHttpClient() + val req = Request.Builder() + .url("$API_URL/user/login") + .post( + ("{ \"username\": \"" + username + "\"," + + "\"password\": \"" + password + "\" }").toRequestBody() + ) + .header("Content-Type", "application/json") + .build() + val loginResponse = client.newCall(req).execute() + val responseBody = loginResponse.body!!.string() + + if (loginResponse.code == 200) { + TOKEN = jsonToLogin.fromJson(responseBody)!!.token + + // Since we are in another thread, we have to get back to the UI thread. + this.runOnUiThread(Runnable { + findViewById(R.id.httpStatus).setTextColor(Color.GREEN) + findViewById(R.id.httpStatus).text = "CONNECTED" + }) + + Snackbar.make(findViewById(R.id.fab), "Login succeeded", Snackbar.LENGTH_SHORT) + .setBackgroundTint(Color.GREEN) + .setActionTextColor(Color.WHITE) + .show() + + checkIfPhoneIsRegistered() + } else { + // Since we are in another thread, we have to get back to the UI thread. + this.runOnUiThread(Runnable { + findViewById(R.id.httpStatus).setTextColor(Color.RED) + findViewById(R.id.httpStatus).text = "LOGIN FAILED" + }) + Snackbar.make(findViewById(R.id.fab), "Login failed", Snackbar.LENGTH_LONG) + .setBackgroundTint(Color.RED) + .setActionTextColor(Color.WHITE) + .show() + } + }) + backendChecks.start() + + /** + * Here we receive updates from our tracker service. + */ + this.broadcastReceiver = object : BroadcastReceiver() { + @SuppressLint("CutPasteId") + override fun onReceive(context: Context, intent: Intent) { + val statusRabbit = intent.getBooleanExtra("statusRabbit", false) + val statusHttp = intent.getIntExtra("statusHttp", 404) + + if (statusRabbit) { + findViewById(R.id.rabbitStatus).text = "connected" + findViewById(R.id.rabbitStatus).setTextColor(Color.GREEN) + } else { + findViewById(R.id.rabbitStatus).text = "disconnected" + findViewById(R.id.rabbitStatus).setTextColor(Color.RED) + } + + if (statusHttp == 200) { + findViewById(R.id.httpStatus).text = "ONLINE (no login)" + findViewById(R.id.httpStatus).setTextColor(Color.CYAN) + findViewById