Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
No results found
Show changes
Commits on Source (10)
Showing
with 363 additions and 91 deletions
...@@ -60,4 +60,6 @@ dependencies { ...@@ -60,4 +60,6 @@ dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
// graph
implementation("com.github.PhilJay:MPAndroidChart:v3.1.0")
} }
\ No newline at end of file
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
android:name="android.hardware.camera" android:name="android.hardware.camera"
android:required="false" /> android:required="false" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
...@@ -26,15 +27,13 @@ ...@@ -26,15 +27,13 @@
android:screenOrientation="portrait"/> android:screenOrientation="portrait"/>
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="false" android:exported="false" />
android:screenOrientation="portrait" />
<activity <activity
android:name=".SplashActivity" android:name=".SplashActivity"
android:exported="true" android:exported="true"
android:screenOrientation="portrait"> android:screenOrientation="portrait">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
...@@ -45,6 +44,13 @@ ...@@ -45,6 +44,13 @@
android:name=".services.JWTExpiry" android:name=".services.JWTExpiry"
android:enabled="true" android:enabled="true"
android:exported="false" /> android:exported="false" />
<receiver
android:name=".services.RandomizeTransaction"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="com.example.bondoman.services.RandomizeTransaction" />
</intent-filter>
</receiver>
</application> </application>
</manifest> </manifest>
\ No newline at end of file
package com.example.bondoman package com.example.bondoman
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController import com.github.mikephil.charting.charts.PieChart
import com.github.mikephil.charting.data.PieData
import com.github.mikephil.charting.data.PieDataSet
import com.github.mikephil.charting.data.PieEntry
class GraphFragment : Fragment() {
class GraphFragment: Fragment() {
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
val navController = findNavController()
// Inflate the layout for this fragment val view = inflater.inflate(R.layout.fragment_grafik, container, false)
return inflater.inflate(R.layout.fragment_grafik, container, false) val pieChart: PieChart = view.findViewById(R.id.pieChart)
// Dummy data
val income = 5000f
val outcome = 3000f
val entries = ArrayList<PieEntry>()
entries.add(PieEntry(income, "Income"))
entries.add(PieEntry(outcome, "Outcome"))
val dataSet = PieDataSet(entries, "Transaction Summary")
val colors = ArrayList<Int>()
colors.add(resources.getColor(R.color.colorIncome))
colors.add(resources.getColor(R.color.colorOutcome))
dataSet.colors = colors
dataSet.valueTextSize = 24f
dataSet.valueTextColor = resources.getColor(R.color.text_graph)
val data = PieData(dataSet)
pieChart.data = data
pieChart.description.isEnabled = false
pieChart.setHoleColor(android.R.color.transparent)
val legend = pieChart.legend
legend.isEnabled = false
pieChart.invalidate()
return view
} }
} }
\ No newline at end of file
package com.example.bondoman package com.example.bondoman
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle import android.os.Bundle
import android.widget.Button import android.widget.Button
...@@ -11,17 +10,16 @@ import android.widget.Toast ...@@ -11,17 +10,16 @@ import android.widget.Toast
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.util.Log import android.util.Log
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.DelicateCoroutinesApi
import com.example.bondoman.models.LoginRequest import com.example.bondoman.models.LoginRequest
import com.example.bondoman.utils.RetrofitInstance import com.example.bondoman.utils.RetrofitInstance
import kotlinx.coroutines.CoroutineScope
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
class LoginActivity : AppCompatActivity() { class LoginActivity : AppCompatActivity() {
@SuppressLint("CommitPrefEdits") @SuppressLint("CommitPrefEdits")
@OptIn(DelicateCoroutinesApi::class) // @OptIn(DelicateCoroutinesApi::class)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login) setContentView(R.layout.activity_login)
...@@ -36,10 +34,8 @@ class LoginActivity : AppCompatActivity() { ...@@ -36,10 +34,8 @@ class LoginActivity : AppCompatActivity() {
val email = "13521010@std.stei.itb.ac.id" val email = "13521010@std.stei.itb.ac.id"
val password = "password_13521010" val password = "password_13521010"
GlobalScope.launch(Dispatchers.Main) { CoroutineScope(Dispatchers.IO).launch {
try { try {
Log.d("LoginActivity", "Email: $email")
Log.d("LoginActivity", "Password: $password")
val response = RetrofitInstance.api.login(LoginRequest(email, password)) val response = RetrofitInstance.api.login(LoginRequest(email, password))
if (response.isSuccessful) { if (response.isSuccessful) {
val token = response.body()?.token val token = response.body()?.token
......
...@@ -7,6 +7,8 @@ import android.view.ViewGroup ...@@ -7,6 +7,8 @@ import android.view.ViewGroup
import android.widget.Button import android.widget.Button
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import android.content.Intent import android.content.Intent
import android.widget.EditText
import com.example.bondoman.services.RandomizeTransaction
class LogoutFragment : Fragment() { class LogoutFragment : Fragment() {
...@@ -19,6 +21,16 @@ class LogoutFragment : Fragment() { ...@@ -19,6 +21,16 @@ class LogoutFragment : Fragment() {
view.findViewById<Button>(R.id.logoutButton).setOnClickListener { view.findViewById<Button>(R.id.logoutButton).setOnClickListener {
logout() logout()
} }
view.findViewById<Button>(R.id.randomButton).setOnClickListener {
val listRandomText = listOf("MacBook Pro", "MacBook Air", "Mac Mini", "Mac Pro", "iMac")
val randomText = listRandomText.random()
val randomizeTransactionIntent = Intent(requireContext(), RandomizeTransaction::class.java)
randomizeTransactionIntent.putExtra("transactionName", randomText)
randomizeTransactionIntent.setAction("com.example.bondoman.services.RandomizeTransaction")
requireContext().sendBroadcast(randomizeTransactionIntent)
}
return view return view
} }
...@@ -36,4 +48,8 @@ class LogoutFragment : Fragment() { ...@@ -36,4 +48,8 @@ class LogoutFragment : Fragment() {
editor.clear() editor.clear()
editor.apply() editor.apply()
} }
fun updateEditText(randomText: String?) {
view?.findViewById<EditText>(R.id.transactionName)?.setText(randomText)
}
} }
\ No newline at end of file
...@@ -3,29 +3,31 @@ package com.example.bondoman ...@@ -3,29 +3,31 @@ package com.example.bondoman
import android.content.Intent import android.content.Intent
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle import android.os.Bundle
import android.view.View
import android.widget.ImageButton import android.widget.ImageButton
import android.widget.Toast
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import com.example.bondoman.services.JWTExpiry import com.example.bondoman.services.JWTExpiry
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.navigation.fragment.NavHostFragment import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.setupActionBarWithNavController import com.example.bondoman.services.ConnectivityObserver
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import com.example.bondoman.services.NetworkSensing
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
private lateinit var service: Intent private lateinit var service: Intent
private lateinit var networkSensing: NetworkSensing
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
service = Intent(this, JWTExpiry::class.java) service = Intent(this, JWTExpiry::class.java)
startService(service) startService(service)
// supportFragmentManager.beginTransaction() networkSensing = NetworkSensing(this)
// .replace(R.id.fragment_container, LogoutFragment())
// .commit()
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
// Get the NavController from the NavHostFragment
val navController = navHostFragment.navController val navController = navHostFragment.navController
val transactionButton = findViewById<ImageButton>(R.id.transaction_button) val transactionButton = findViewById<ImageButton>(R.id.transaction_button)
...@@ -66,6 +68,19 @@ class MainActivity : AppCompatActivity() { ...@@ -66,6 +68,19 @@ class MainActivity : AppCompatActivity() {
startActivity(intent) startActivity(intent)
} }
networkSensing.observe()
.onEach { state ->
when (state) {
ConnectivityObserver.NetworkState.CONNECTED -> {
Toast.makeText(this, "Connected", Toast.LENGTH_SHORT).show()
}
ConnectivityObserver.NetworkState.DISCONNECTED -> {
Toast.makeText(this, "Disconnected", Toast.LENGTH_SHORT).show()
}
}
}
.launchIn(lifecycleScope)
} }
override fun onSupportNavigateUp(): Boolean { override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment) val navController = findNavController(R.id.nav_host_fragment)
......
...@@ -5,6 +5,7 @@ import android.content.ContentValues.TAG ...@@ -5,6 +5,7 @@ import android.content.ContentValues.TAG
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.graphics.ImageFormat import android.graphics.ImageFormat
import android.graphics.SurfaceTexture import android.graphics.SurfaceTexture
...@@ -13,9 +14,13 @@ import android.hardware.camera2.CameraDevice ...@@ -13,9 +14,13 @@ import android.hardware.camera2.CameraDevice
import android.hardware.camera2.CameraManager import android.hardware.camera2.CameraManager
import android.hardware.camera2.CaptureRequest import android.hardware.camera2.CaptureRequest
import android.hardware.camera2.TotalCaptureResult import android.hardware.camera2.TotalCaptureResult
import android.hardware.camera2.params.OutputConfiguration
import android.hardware.camera2.params.SessionConfiguration
import android.media.ImageReader import android.media.ImageReader
import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Environment
import android.os.Handler import android.os.Handler
import android.os.HandlerThread import android.os.HandlerThread
import android.util.Log import android.util.Log
...@@ -23,21 +28,33 @@ import android.view.Surface ...@@ -23,21 +28,33 @@ import android.view.Surface
import android.view.TextureView import android.view.TextureView
import android.view.View import android.view.View
import android.widget.ImageButton import android.widget.ImageButton
import android.widget.ImageView
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import com.example.bondoman.models.ScanRequest
import com.example.bondoman.utils.RetrofitInstance
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import okhttp3.MediaType
import okhttp3.MultipartBody
import okhttp3.RequestBody
import retrofit2.HttpException
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.util.concurrent.Executors
class ScanActivity : ComponentActivity() { class ScanActivity : ComponentActivity() {
private var isLivePreview = true
lateinit var capReq: CaptureRequest.Builder lateinit var capReq: CaptureRequest.Builder
lateinit var handler: Handler private lateinit var handler: Handler
private lateinit var handlerThread: HandlerThread private lateinit var handlerThread: HandlerThread
private lateinit var cameraManager: CameraManager private lateinit var cameraManager: CameraManager
lateinit var textureView: TextureView lateinit var textureView: TextureView
lateinit var cameraCaptureSession: CameraCaptureSession lateinit var cameraCaptureSession: CameraCaptureSession
lateinit var cameraDevice: CameraDevice lateinit var cameraDevice: CameraDevice
// lateinit var captureRequest: CaptureRequest
lateinit var imageReader: ImageReader lateinit var imageReader: ImageReader
private lateinit var captureButton: ImageButton private lateinit var captureButton: ImageButton
...@@ -45,8 +62,9 @@ class ScanActivity : ComponentActivity() { ...@@ -45,8 +62,9 @@ class ScanActivity : ComponentActivity() {
private lateinit var galleryButton: ImageButton private lateinit var galleryButton: ImageButton
private lateinit var confirmButton: ImageButton private lateinit var confirmButton: ImageButton
private lateinit var imageFile: File
private var job: Job? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
...@@ -64,6 +82,9 @@ class ScanActivity : ComponentActivity() { ...@@ -64,6 +82,9 @@ class ScanActivity : ComponentActivity() {
cameraDevice.close() cameraDevice.close()
handler.removeCallbacksAndMessages(null) handler.removeCallbacksAndMessages(null)
handlerThread.quitSafely() handlerThread.quitSafely()
textureView.surfaceTexture?.release()
textureView.surfaceTextureListener = null
} }
private fun configureCameraPreview() { private fun configureCameraPreview() {
...@@ -74,7 +95,12 @@ class ScanActivity : ComponentActivity() { ...@@ -74,7 +95,12 @@ class ScanActivity : ComponentActivity() {
capReq = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) capReq = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
val surface = Surface(textureView.surfaceTexture) val surface = Surface(textureView.surfaceTexture)
capReq.addTarget(surface) capReq.addTarget(surface)
cameraDevice.createCaptureSession(listOf(surface, imageReader.surface), val outputConfigurationSurface = OutputConfiguration(surface)
val outputConfigurationImageReader = OutputConfiguration(imageReader.surface)
val sessionConfiguration = SessionConfiguration(
SessionConfiguration.SESSION_REGULAR,
listOf(outputConfigurationSurface, outputConfigurationImageReader),
Executors.newSingleThreadExecutor(),
object : CameraCaptureSession.StateCallback() { object : CameraCaptureSession.StateCallback() {
override fun onConfigured(session: CameraCaptureSession) { override fun onConfigured(session: CameraCaptureSession) {
cameraCaptureSession = session cameraCaptureSession = session
...@@ -82,11 +108,12 @@ class ScanActivity : ComponentActivity() { ...@@ -82,11 +108,12 @@ class ScanActivity : ComponentActivity() {
} }
override fun onConfigureFailed(session: CameraCaptureSession) { override fun onConfigureFailed(session: CameraCaptureSession) {
// Handle configuration failure
} }
}
)
}, handler) cameraDevice.createCaptureSession(sessionConfiguration)
isLivePreview = true
} }
...@@ -100,6 +127,10 @@ class ScanActivity : ComponentActivity() { ...@@ -100,6 +127,10 @@ class ScanActivity : ComponentActivity() {
buffer.get(bytes) buffer.get(bytes)
val bitmapImage = BitmapFactory.decodeByteArray(bytes, 0, bytes.size) val bitmapImage = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
// Save the image as a File
// val file = File(getExternalFilesDir(null), "selectedImage.jpg")
// file.writeBytes(bytes)
// imageFile = file // Assuming imageFile is a class attribute
// Display the captured image on your TextureView // Display the captured image on your TextureView
runOnUiThread { runOnUiThread {
textureView.surfaceTexture?.let { _ -> textureView.surfaceTexture?.let { _ ->
...@@ -112,11 +143,35 @@ class ScanActivity : ComponentActivity() { ...@@ -112,11 +143,35 @@ class ScanActivity : ComponentActivity() {
} }
} }
} }
// Close and release the Image when done // Close and release the Image when done
image.close() image.close()
} }
private fun displayUploadedImage(uri: Uri) {
captureButton.visibility = View.INVISIBLE
galleryButton.visibility = View.INVISIBLE
recaptureButton.visibility = View.VISIBLE
confirmButton.visibility = View.VISIBLE
val imageView = findViewById<ImageView>(R.id.imageView)
imageView.setImageURI(uri)
imageView.visibility = View.VISIBLE
textureView.visibility = View.GONE
// val parcelFileDescriptor = contentResolver.openFileDescriptor(uri, "r")
// val fileDescriptor = parcelFileDescriptor?.fileDescriptor
// val file = File(cacheDir, "MyImage.jpg")
// val inputStream = FileInputStream(fileDescriptor)
// val outputStream = FileOutputStream(file)
// inputStream.copyTo(outputStream)
// imageFile = file // Assuming imageFile is a class attribute
}
private val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
if (uri != null) {
displayUploadedImage(uri)
}
}
private fun openCamera(){ private fun openCamera(){
if (ActivityCompat.checkSelfPermission( if (ActivityCompat.checkSelfPermission(
...@@ -135,7 +190,12 @@ class ScanActivity : ComponentActivity() { ...@@ -135,7 +190,12 @@ class ScanActivity : ComponentActivity() {
capReq = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) capReq = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
val surface = Surface(textureView.surfaceTexture) val surface = Surface(textureView.surfaceTexture)
capReq.addTarget(surface) capReq.addTarget(surface)
cameraDevice.createCaptureSession(listOf(surface, imageReader.surface), val outputConfigurationSurface = OutputConfiguration(surface)
val outputConfigurationImageReader = OutputConfiguration(imageReader.surface)
val sessionConfiguration = SessionConfiguration(
SessionConfiguration.SESSION_REGULAR,
listOf(outputConfigurationSurface, outputConfigurationImageReader),
Executors.newSingleThreadExecutor(),
object : CameraCaptureSession.StateCallback() { object : CameraCaptureSession.StateCallback() {
override fun onConfigured(session: CameraCaptureSession) { override fun onConfigured(session: CameraCaptureSession) {
cameraCaptureSession = session cameraCaptureSession = session
...@@ -143,10 +203,12 @@ class ScanActivity : ComponentActivity() { ...@@ -143,10 +203,12 @@ class ScanActivity : ComponentActivity() {
} }
override fun onConfigureFailed(session: CameraCaptureSession) { override fun onConfigureFailed(session: CameraCaptureSession) {
// Handle configuration failure
} }
}
)
}, handler) cameraDevice.createCaptureSession(sessionConfiguration)
} }
override fun onDisconnected(camera: CameraDevice) { override fun onDisconnected(camera: CameraDevice) {
...@@ -199,33 +261,67 @@ class ScanActivity : ComponentActivity() { ...@@ -199,33 +261,67 @@ class ScanActivity : ComponentActivity() {
imageReader = ImageReader.newInstance(1080, 1323, ImageFormat.JPEG, 1) imageReader = ImageReader.newInstance(1080, 1323, ImageFormat.JPEG, 1)
captureButton.apply { captureButton.setOnClickListener {
setOnClickListener { captureButton.visibility = View.INVISIBLE
captureButton.visibility = View.INVISIBLE galleryButton.visibility = View.INVISIBLE
galleryButton.visibility = View.INVISIBLE recaptureButton.visibility = View.VISIBLE
recaptureButton.visibility = View.VISIBLE confirmButton.visibility = View.VISIBLE
confirmButton.visibility = View.VISIBLE capReq = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE)
capReq = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE) capReq.addTarget(imageReader.surface)
capReq.addTarget(imageReader.surface) cameraCaptureSession.capture(capReq.build(), object : CameraCaptureSession.CaptureCallback() {
cameraCaptureSession.capture(capReq.build(), object : CameraCaptureSession.CaptureCallback() { override fun onCaptureCompleted(session: CameraCaptureSession, request: CaptureRequest, result: TotalCaptureResult) {
override fun onCaptureCompleted(session: CameraCaptureSession, request: CaptureRequest, result: TotalCaptureResult) { super.onCaptureCompleted(session, request, result)
super.onCaptureCompleted(session, request, result) displayCapturedImage()
displayCapturedImage() }
} }, null)
}, null) }
}
recaptureButton.setOnClickListener {
captureButton.visibility = View.VISIBLE
galleryButton.visibility = View.VISIBLE
recaptureButton.visibility = View.INVISIBLE
confirmButton.visibility = View.INVISIBLE
textureView.visibility = View.VISIBLE
findViewById<ImageView>(R.id.imageView).visibility = View.GONE
configureCameraPreview()
} }
recaptureButton.apply {
setOnClickListener { galleryButton.setOnClickListener {
captureButton.visibility = View.VISIBLE getContent.launch("image/*")
galleryButton.visibility = View.VISIBLE }
recaptureButton.visibility = View.INVISIBLE
confirmButton.visibility = View.INVISIBLE confirmButton.setOnClickListener {
configureCameraPreview() job = CoroutineScope(Dispatchers.IO).launch {
val sharedPreferences = getSharedPreferences("sharedPrefs", Context.MODE_PRIVATE)
val token = sharedPreferences.getString("TOKEN", "") ?: ""
try {
val requestFile = RequestBody.create(
MediaType.parse("image/jpg"),
imageFile
)
val body = MultipartBody.Part.createFormData("file", imageFile.name, requestFile)
val response = RetrofitInstance.api.uploadFile(token, body) // replace "your_token" with the actual token
if (response.isSuccessful) {
// Get the response body
val responseBody = response.body()
// Convert the response body to a string and print it
Log.d(TAG, responseBody.toString())
} else {
// Handle the error response
println("Error: ${response.errorBody()?.string()}")
}
} catch (e: HttpException) {
Log.e(TAG, e.message())
} catch (e: Throwable) {
Log.e(TAG, e.stackTraceToString())
}
} }
} }
} else { } else {
val intent = Intent(this, MainActivity::class.java) val intent = Intent(this, MainActivity::class.java)
startActivity(intent) startActivity(intent)
...@@ -233,16 +329,6 @@ class ScanActivity : ComponentActivity() { ...@@ -233,16 +329,6 @@ class ScanActivity : ComponentActivity() {
} }
} }
private fun hasRequiredPermissions(): Boolean {
return CAMERA_PERMISSION.all {
ContextCompat.checkSelfPermission(
applicationContext,
it
) == PackageManager.PERMISSION_GRANTED
}
}
companion object { companion object {
private val CAMERA_PERMISSION = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { private val CAMERA_PERMISSION = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
arrayOf( arrayOf(
...@@ -253,6 +339,7 @@ class ScanActivity : ComponentActivity() { ...@@ -253,6 +339,7 @@ class ScanActivity : ComponentActivity() {
arrayOf( arrayOf(
Manifest.permission.CAMERA, Manifest.permission.CAMERA,
Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
) )
} }
} }
......
...@@ -5,10 +5,13 @@ import com.example.bondoman.models.LoginResponse ...@@ -5,10 +5,13 @@ import com.example.bondoman.models.LoginResponse
import com.example.bondoman.models.JWTResponse import com.example.bondoman.models.JWTResponse
import com.example.bondoman.models.ScanRequest import com.example.bondoman.models.ScanRequest
import com.example.bondoman.models.ScanResponse import com.example.bondoman.models.ScanResponse
import okhttp3.MultipartBody
import retrofit2.Response import retrofit2.Response
import retrofit2.http.POST import retrofit2.http.POST
import retrofit2.http.Body import retrofit2.http.Body
import retrofit2.http.Header import retrofit2.http.Header
import retrofit2.http.Multipart
import retrofit2.http.Part
import java.io.File import java.io.File
interface ApiInterface { interface ApiInterface {
...@@ -18,6 +21,10 @@ interface ApiInterface { ...@@ -18,6 +21,10 @@ interface ApiInterface {
@POST("/api/auth/token") @POST("/api/auth/token")
suspend fun jwt(@Header("Authorization") token: String): Response<JWTResponse> suspend fun jwt(@Header("Authorization") token: String): Response<JWTResponse>
@POST("/api/bill/upload") @Multipart
suspend fun scan(@Body scanRequest: ScanRequest): Response<ScanResponse> @POST("api/bill/upload")
suspend fun uploadFile(
@Header("Token") token: String,
@Part file: MultipartBody.Part
): Response<List<ScanResponse>>
} }
\ No newline at end of file
package com.example.bondoman.services
import kotlinx.coroutines.flow.Flow
interface ConnectivityObserver {
fun observe() : Flow<NetworkState>
enum class NetworkState {
CONNECTED, DISCONNECTED
}
}
\ No newline at end of file
...@@ -65,10 +65,6 @@ class JWTExpiry : Service() { ...@@ -65,10 +65,6 @@ class JWTExpiry : Service() {
Log.e("JWTExpiry", "HTTP Exception: ${e.message()}") Log.e("JWTExpiry", "HTTP Exception: ${e.message()}")
redirectToLogin() redirectToLogin()
break break
} catch (e: Throwable) {
Log.e("JWTExpiry", "Error: ${e.message}")
redirectToLogin()
break
} }
} }
} }
......
package com.example.bondoman.services
import android.content.Context
import android.net.ConnectivityManager
import kotlinx.coroutines.flow.Flow
import com.example.bondoman.services.ConnectivityObserver.NetworkState
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import android.net.Network
class NetworkSensing (private val context: Context) : ConnectivityObserver {
private val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
override fun observe(): Flow<NetworkState> {
return callbackFlow {
val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
trySend(NetworkState.CONNECTED)
}
override fun onLost(network: Network) {
trySend(NetworkState.DISCONNECTED)
}
}
connectivityManager.registerDefaultNetworkCallback(networkCallback)
awaitClose { connectivityManager.unregisterNetworkCallback(networkCallback) }
}.distinctUntilChanged()
}
}
\ No newline at end of file
package com.example.bondoman.services
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity
import com.example.bondoman.LogoutFragment
import com.example.bondoman.R
class RandomizeTransaction : BroadcastReceiver() {
private var text: String = ""
override fun onReceive(context: Context?, intent: Intent?) {
text = intent?.getStringExtra("transactionName").toString()
Log.d("BroadcastRandomizeTransaction", "Random text: $text")
// val activity = context as? AppCompatActivity
// activity?.runOnUiThread {
// val fragment = activity.supportFragmentManager.findFragmentById(R.id.fragment_container) as? LogoutFragment
// fragment?.updateEditText(randomText)
// }
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000113">
<com.github.mikephil.charting.charts.PieChart
android:id="@+id/pieChart"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="16dp"/>
</RelativeLayout>
...@@ -16,11 +16,21 @@ ...@@ -16,11 +16,21 @@
android:layout_marginTop="100dp" android:layout_marginTop="100dp"
android:layout_marginBottom="200dp" android:layout_marginBottom="200dp"
android:orientation="horizontal" android:orientation="horizontal"
android:layout_centerHorizontal="true"
android:background="@drawable/effect_rounded_edge"> android:background="@drawable/effect_rounded_edge">
<TextureView <TextureView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:id="@+id/textureView"/> android:id="@+id/textureView"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitCenter"
android:adjustViewBounds="true"
android:id="@+id/imageView"
android:visibility="gone"/>
<View <View
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"> android:background="#000113">
<TextView <com.github.mikephil.charting.charts.PieChart
android:layout_width="wrap_content" android:id="@+id/pieChart"
android:layout_height="wrap_content" android:layout_width="match_parent"
app:layout_constraintTop_toTopOf="parent" android:layout_height="match_parent"
app:layout_constraintStart_toStartOf="parent" android:layout_marginBottom="16dp"/>
app:layout_constraintEnd_toEndOf="parent"
android:text="@string/graph_button_description">
</TextView>
</androidx.constraintlayout.widget.ConstraintLayout> </RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
...@@ -6,7 +6,25 @@ ...@@ -6,7 +6,25 @@
<Button <Button
android:id="@+id/logoutButton" android:id="@+id/logoutButton"
android:layout_width="wrap_content" android:layout_width="200dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/logout"/> android:text="@string/logout" />
<EditText
android:id="@+id/transactionName"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_below="@+id/logoutButton"
android:layout_marginTop="20dp"
android:autofillHints=""
android:hint="@string/transaction_name"
android:inputType="text" />
<Button
android:id="@+id/randomButton"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:text="@string/randomize"
android:layout_below="@+id/transactionName"
android:layout_marginTop="20dp" />
</RelativeLayout> </RelativeLayout>
\ No newline at end of file
...@@ -11,4 +11,7 @@ ...@@ -11,4 +11,7 @@
<color name="light_purple">#9290C3</color> <color name="light_purple">#9290C3</color>
<color name="light_grey">#EAEAEA</color> <color name="light_grey">#EAEAEA</color>
<color name="text_grey">#475569</color> <color name="text_grey">#475569</color>
<color name="colorIncome">#1B1A55</color>
<color name="colorOutcome">#9290C3</color>
<color name="text_graph">#5852EE</color>
</resources> </resources>
\ No newline at end of file
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
<string name="hint_input_email_address">Input Email Address</string> <string name="hint_input_email_address">Input Email Address</string>
<string name="hint_input_password">Input Password</string> <string name="hint_input_password">Input Password</string>
<string name="logout">Logout</string> <string name="logout">Logout</string>
<string name="transaction_name">Transaction Name</string>
<string name="randomize">Randomize</string>
<string name="transaction_button_description">Transaksi</string> <string name="transaction_button_description">Transaksi</string>
<string name="graph_button_description">Grafik</string> <string name="graph_button_description">Grafik</string>
<string name="setting_button_description">Pengaturan</string> <string name="setting_button_description">Pengaturan</string>
...@@ -11,8 +13,5 @@ ...@@ -11,8 +13,5 @@
<string name="rescan_button_description">Pindai Ulang</string> <string name="rescan_button_description">Pindai Ulang</string>
<string name="image_button_description">Galeri</string> <string name="image_button_description">Galeri</string>
<string name="confirm_button_description">Konfirmasi</string> <string name="confirm_button_description">Konfirmasi</string>
<!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string> <string name="hello_blank_fragment">Hello blank fragment</string>
</resources> </resources>
\ No newline at end of file
...@@ -3,6 +3,7 @@ pluginManagement { ...@@ -3,6 +3,7 @@ pluginManagement {
google() google()
mavenCentral() mavenCentral()
gradlePluginPortal() gradlePluginPortal()
maven("https://jitpack.io")
} }
} }
dependencyResolutionManagement { dependencyResolutionManagement {
...@@ -10,6 +11,7 @@ dependencyResolutionManagement { ...@@ -10,6 +11,7 @@ dependencyResolutionManagement {
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
maven("https://jitpack.io")
} }
} }
......