diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 723ad5a706cd49c7bb3b69b94d2024ddcda4c0e2..6893ebaa600a1c554b97fba90932b2854171ffb3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -22,21 +22,22 @@ tools:targetApi="31"> <activity android:name=".MainActivity" - android:exported="true"> + android:exported="false"> + </activity> + <activity + android:name=".ui.login.LoginActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> - </activity> - <activity - android:name=".ui.login.LoginActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> + <provider android:name="androidx.core.content.FileProvider" android:authorities="com.example.abe.fileprovider" @@ -46,6 +47,7 @@ android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths" /> </provider> + <service android:name=".services.AuthService" android:exported="false" /> </application> <queries> diff --git a/app/src/main/java/com/example/abe/MainActivity.kt b/app/src/main/java/com/example/abe/MainActivity.kt index e3c109014161bb60c3a41658f5777d1e9fb59250..dc6b6febd4db1fe36686747c85f54e8a8ec1c72e 100644 --- a/app/src/main/java/com/example/abe/MainActivity.kt +++ b/app/src/main/java/com/example/abe/MainActivity.kt @@ -1,11 +1,13 @@ package com.example.abe import android.app.Activity +import android.app.AlertDialog import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter import android.os.Bundle +import android.util.Log import android.widget.Toast import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.viewModels @@ -19,16 +21,23 @@ import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.navigateUp import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupWithNavController +import com.example.abe.connection.ConnectivityObserver +import com.example.abe.connection.NetworkConnectivityObserver import com.example.abe.databinding.ActivityMainBinding +import com.example.abe.services.AuthService import com.example.abe.types.FragmentListener +import com.example.abe.ui.login.LoginActivity import com.example.abe.ui.transactions.ExportAlertDialogFragment import com.example.abe.ui.transactions.ExportAlertDialogTypeEnum import com.example.abe.ui.transactions.ExportLoadDialogFragment import com.example.abe.ui.transactions.TransactionFragment import com.google.android.material.bottomnavigation.BottomNavigationView +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch -class MainActivity : AppCompatActivity(), ExportAlertDialogFragment.ExportAlertDialogListener, FragmentListener, TransactionFragment.ItemClickListener { +class MainActivity : AppCompatActivity(), ExportAlertDialogFragment.ExportAlertDialogListener, + FragmentListener, TransactionFragment.ItemClickListener { private lateinit var appBarConfiguration: AppBarConfiguration private lateinit var navController: NavController @@ -37,16 +46,31 @@ class MainActivity : AppCompatActivity(), ExportAlertDialogFragment.ExportAlertD MainActivityViewModelFactory((application as ABEApplication).repository) } - private val filter = IntentFilter().apply { addAction("RANDOMIZE_TRANSACTION") } + private lateinit var connectivityObserver: ConnectivityObserver + private lateinit var networkState:ConnectivityObserver.NetworkState + + private val filter = IntentFilter().apply { + addAction("RANDOMIZE_TRANSACTION") + addAction("EXPIRED_TOKEN") + } private val br = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { - when(intent.action) { + when (intent.action) { "RANDOMIZE_TRANSACTION" -> { val randomAmount = intent.getIntExtra("random_amount", 0) val bundle = Bundle().apply { putInt("random_amount", randomAmount) } - navController.navigate(R.id.action_navigation_transactions_to_navigation_form_transaction, bundle) + navController.navigate( + R.id.action_navigation_transactions_to_navigation_form_transaction, + bundle + ) + } + + "EXPIRED_TOKEN" -> { + val loginIntent = Intent(context, LoginActivity::class.java) + startActivity(loginIntent) + this@MainActivity.finish() } } } @@ -73,10 +97,33 @@ class MainActivity : AppCompatActivity(), ExportAlertDialogFragment.ExportAlertD navView.setupWithNavController(navController) LocalBroadcastManager.getInstance(this).registerReceiver(br, filter) + + val serviceIntent = Intent(this, AuthService::class.java) + startService(serviceIntent); + + connectivityObserver = NetworkConnectivityObserver(applicationContext) + connectivityObserver.observe().onEach { + networkState = it + Log.v("abecekut", "Status is $it") + if (it == ConnectivityObserver.NetworkState.UNAVAILABLE || it == ConnectivityObserver.NetworkState.LOST) { + runOnUiThread { + val builder: AlertDialog.Builder = AlertDialog.Builder(this@MainActivity) + builder + .setMessage("We are having trouble connecting you to the internet") + .setTitle("No Connection") + .setPositiveButton("OK") { dialog, which -> + // Do something. + } + + val dialog: AlertDialog = builder.create() + dialog.show() + } + } + }.launchIn(lifecycleScope) } override fun onIntentReceived(action: String, info: String?) { - when(action) { + when (action) { "OPEN_FORM" -> { navController.navigate(R.id.action_navigation_transactions_to_navigation_form_transaction) } @@ -87,8 +134,12 @@ class MainActivity : AppCompatActivity(), ExportAlertDialogFragment.ExportAlertD val bundle = Bundle() bundle.putBoolean("is-update", true) bundle.putInt("idx-id", id) - navController.navigate(R.id.action_navigation_transactions_to_navigation_form_transaction, bundle) + navController.navigate( + R.id.action_navigation_transactions_to_navigation_form_transaction, + bundle + ) } + override fun onNewExcelFormatClick(dialog: DialogFragment, type: ExportAlertDialogTypeEnum) { viewModel.newExcelFormat = true when (type) { @@ -156,6 +207,8 @@ class MainActivity : AppCompatActivity(), ExportAlertDialogFragment.ExportAlertD override fun onDestroy() { super.onDestroy() LocalBroadcastManager.getInstance(this).registerReceiver(br, filter) + val serviceIntent = Intent(this, AuthService::class.java) + stopService(serviceIntent); } override fun onSupportNavigateUp(): Boolean { diff --git a/app/src/main/java/com/example/abe/connection/ConnectivityObserver.kt b/app/src/main/java/com/example/abe/connection/ConnectivityObserver.kt new file mode 100644 index 0000000000000000000000000000000000000000..4ef3aedcfdbe6fd833d0caf41b729fe88593d879 --- /dev/null +++ b/app/src/main/java/com/example/abe/connection/ConnectivityObserver.kt @@ -0,0 +1,13 @@ +package com.example.abe.connection + +import kotlinx.coroutines.flow.Flow + + +interface ConnectivityObserver { + + fun observe(): Flow<NetworkState> + + enum class NetworkState { + AVAILABLE, UNAVAILABLE, LOSING, LOST + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/abe/connection/NetworkConnectivityObserver.kt b/app/src/main/java/com/example/abe/connection/NetworkConnectivityObserver.kt new file mode 100644 index 0000000000000000000000000000000000000000..e3a19da9ed3309fc6417b4d47f17beba47d875e8 --- /dev/null +++ b/app/src/main/java/com/example/abe/connection/NetworkConnectivityObserver.kt @@ -0,0 +1,45 @@ +package com.example.abe.connection + +import android.content.Context +import android.net.ConnectivityManager +import android.net.Network +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.launch + +class NetworkConnectivityObserver(private val context: Context): ConnectivityObserver { + private val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + + override fun observe(): Flow<ConnectivityObserver.NetworkState> { + return callbackFlow { + val callback = object : ConnectivityManager.NetworkCallback() { + override fun onAvailable(network: Network) { + super.onAvailable(network) + launch { send(ConnectivityObserver.NetworkState.AVAILABLE) } + } + + override fun onLosing(network: Network, maxMsToLive: Int) { + super.onLosing(network, maxMsToLive) + launch { send(ConnectivityObserver.NetworkState.LOSING) } + } + + override fun onLost(network: Network) { + super.onLost(network) + launch { send(ConnectivityObserver.NetworkState.LOST) } + } + + override fun onUnavailable() { + super.onUnavailable() + launch { send(ConnectivityObserver.NetworkState.UNAVAILABLE) } + } + } + + connectivityManager.registerDefaultNetworkCallback(callback) + awaitClose { + connectivityManager.unregisterNetworkCallback(callback) + } + }.distinctUntilChanged() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/abe/data/network/Retrofit.kt b/app/src/main/java/com/example/abe/data/network/Retrofit.kt index 990c70aaecf393c48a6b48b8e2e9ecedd88fa242..74183caab491b46d3ffa1dbd29c8315288bb3d68 100644 --- a/app/src/main/java/com/example/abe/data/network/Retrofit.kt +++ b/app/src/main/java/com/example/abe/data/network/Retrofit.kt @@ -4,6 +4,9 @@ import android.content.Context import okhttp3.MediaType import okhttp3.MultipartBody import okhttp3.RequestBody +import android.preference.PreferenceManager +import com.example.abe.R +import com.example.abe.services.AuthService import retrofit2.Call import retrofit2.Callback import retrofit2.Response @@ -19,6 +22,32 @@ interface LoginResultCallback { interface UploadResultCallback { fun onSuccess(uploadResponse: ItemsRoot) fun onFailure(errorMessage: String) + +interface CheckAuthResultCallback { + fun onFailure() +} + +class CallBack<T> : Callback<T> { + override fun onResponse(call: Call<T>, response: Response<T>) { + if (response.isSuccessful) { + // Handle successful response + val data = response.body() + // Process the data here + if (data is LoginResponse) { + // Handle LoginResponse + println("Login successful $data") + } + } else { + // Handle error response + // Maybe use response.errorBody() to get error details + println("Login failed") + } + } + + override fun onFailure(call: Call<T>, t: Throwable) { + // Handle failure + println("Failed to send request") + } } class Retrofit { @@ -82,4 +111,20 @@ class Retrofit { }) } + fun checkAuth(token: String, callback: CheckAuthResultCallback) { + val checkAuthService = retrofit.create(CheckAuthService::class.java) + val call: Call<CheckAuthResponse> = checkAuthService.checkAuth("Bearer $token") + + call.enqueue(object : Callback<CheckAuthResponse> { + override fun onResponse(call: Call<CheckAuthResponse>, response: Response<CheckAuthResponse>) { + if (!response.isSuccessful) { + callback.onFailure() + } + } + + override fun onFailure(call: Call<CheckAuthResponse>, t: Throwable) { + callback.onFailure() + } + }) + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/abe/data/network/Services.kt b/app/src/main/java/com/example/abe/data/network/Services.kt index 06b52e08a7758c0f5e5afc7992ef39a99507ea6d..9bed1c0b4c79603b8a9ef4fa01e04e687e7d65b0 100644 --- a/app/src/main/java/com/example/abe/data/network/Services.kt +++ b/app/src/main/java/com/example/abe/data/network/Services.kt @@ -20,4 +20,8 @@ interface ScannerService { @Header("Authorization") authHeader: String, @Part file: MultipartBody.Part ): Call<ItemsRoot> + +interface CheckAuthService { + @POST("api/auth/token") + fun checkAuth(@Header("Authorization") token: String) : Call<CheckAuthResponse> } \ No newline at end of file diff --git a/app/src/main/java/com/example/abe/data/network/Types.kt b/app/src/main/java/com/example/abe/data/network/Types.kt index e7a2e2613656f164565b3c7a41f48d4676f88076..e423b33a53a42e4b94da8eb9e738d55f86da2f47 100644 --- a/app/src/main/java/com/example/abe/data/network/Types.kt +++ b/app/src/main/java/com/example/abe/data/network/Types.kt @@ -22,3 +22,9 @@ data class ItemsContainer( data class ItemsRoot( val items: ItemsContainer ) + +data class CheckAuthResponse ( + val nim: String, + val iat: String, + val exp: String +) diff --git a/app/src/main/java/com/example/abe/services/AuthService.kt b/app/src/main/java/com/example/abe/services/AuthService.kt new file mode 100644 index 0000000000000000000000000000000000000000..c2201ee384d85faa55632fed1156a035349f4b4e --- /dev/null +++ b/app/src/main/java/com/example/abe/services/AuthService.kt @@ -0,0 +1,50 @@ +package com.example.abe.services + +import android.app.Service +import android.content.Context +import android.content.Intent + +import android.os.IBinder +import android.util.Log +import androidx.core.content.ContentProviderCompat.requireContext +import androidx.localbroadcastmanager.content.LocalBroadcastManager +import com.example.abe.R +import com.example.abe.data.network.CheckAuthResponse +import com.example.abe.data.network.CheckAuthResultCallback +import com.example.abe.data.network.Retrofit + + +class AuthService : Service(), CheckAuthResultCallback { + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + Thread { + while (true) { + Log.v("Servicecekut", "Service is running...") + val retrofit = Retrofit() + val sharedPref = getSharedPreferences( + getString(R.string.preference_file_key), + Context.MODE_PRIVATE + ) + val token = sharedPref.getString("login_token", "").toString() + Log.v("Servicecekut", token) + retrofit.checkAuth(token, this) + try { + Thread.sleep(30000) + } catch (e: InterruptedException) { + e.printStackTrace() + } + } + }.start() + return START_NOT_STICKY + } + + override fun onBind(intent: Intent?): IBinder? { + return null + } + + override fun onFailure() { + Intent().also { intent -> + intent.setAction("EXPIRED_TOKEN") + LocalBroadcastManager.getInstance(applicationContext).sendBroadcast(intent) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/abe/services/auth.kt b/app/src/main/java/com/example/abe/services/login.kt similarity index 100% rename from app/src/main/java/com/example/abe/services/auth.kt rename to app/src/main/java/com/example/abe/services/login.kt diff --git a/app/src/main/java/com/example/abe/ui/form_transaction/FormTransaction.kt b/app/src/main/java/com/example/abe/ui/form_transaction/FormTransaction.kt index d22f32ee28399cf6cd8acb10692ff4cc8c50db2c..d29c659c64b508b2c3badddea6bf84b787757016 100644 --- a/app/src/main/java/com/example/abe/ui/form_transaction/FormTransaction.kt +++ b/app/src/main/java/com/example/abe/ui/form_transaction/FormTransaction.kt @@ -9,6 +9,7 @@ import android.location.Address import android.location.Geocoder import android.location.Location import android.location.LocationManager +import android.net.Uri import android.os.Bundle import android.provider.Settings import android.util.Log @@ -19,6 +20,7 @@ import android.widget.AdapterView import android.widget.ArrayAdapter import android.widget.Toast import androidx.activity.addCallback +import androidx.constraintlayout.widget.ConstraintSet import androidx.core.app.ActivityCompat import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels @@ -81,6 +83,7 @@ class FormTransaction : Fragment() { titleFocusListener() amountFocusListener() categoryFocusListener() + openInMapListener() locationFocusListener() saveButtonListener() @@ -101,15 +104,25 @@ class FormTransaction : Fragment() { displayTrx(trxId) } else if (args.containsKey("random_amount")) { viewModel.setRandomAmount(args.getInt("random_amount")) - binding.btnDelete.visibility = View.GONE + useNewTrxLayout() } } else { - binding.btnDelete.visibility = View.GONE + useNewTrxLayout() } return binding.root } + private fun useNewTrxLayout() { + binding.btnDelete.visibility = View.GONE + binding.btnOpenMap.visibility = View.GONE + + ConstraintSet().apply { + clone(binding.formTransaction) + connect(R.id.formLocationContainer, ConstraintSet.TOP, R.id.formCategoryContainer, ConstraintSet.BOTTOM, 5) + applyTo(binding.formTransaction) + } + } private fun displayTrx(idTrx: Int) { id = idTrx @@ -150,6 +163,17 @@ class FormTransaction : Fragment() { } } + private fun openInMapListener() { + binding.btnOpenMap.setOnClickListener { + val destinationLatitude = viewModel.latitude.value.toString() + val destinationLongitude = viewModel.longitude.value.toString() + + val mapUri = Uri.parse("https://maps.google.com/maps?daddr=$destinationLatitude,$destinationLongitude") + val intent = Intent(Intent.ACTION_VIEW, mapUri) + startActivity(intent) + } + } + private fun locationFocusListener() { binding.formLocationEditText.setOnFocusChangeListener { _, focused -> if (!focused) { diff --git a/app/src/main/java/com/example/abe/ui/login/LoginActivity.kt b/app/src/main/java/com/example/abe/ui/login/LoginActivity.kt index bd2385cc1a5268065fba188af94665bac7760b0f..efab5113cf8eacf0487ee1069a405484566224da 100644 --- a/app/src/main/java/com/example/abe/ui/login/LoginActivity.kt +++ b/app/src/main/java/com/example/abe/ui/login/LoginActivity.kt @@ -3,12 +3,23 @@ package com.example.abe.ui.login import android.content.Context import android.content.Intent import android.os.Bundle +import android.util.Log +import android.view.View +import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.asLiveData +import androidx.lifecycle.lifecycleScope import com.example.abe.MainActivity import com.example.abe.R +import com.example.abe.connection.ConnectivityObserver +import com.example.abe.connection.NetworkConnectivityObserver import com.example.abe.data.network.LoginResultCallback import com.example.abe.data.network.Retrofit import com.example.abe.databinding.ActivityLoginBinding +import com.example.abe.utils.isConnected +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach class LoginActivity : AppCompatActivity(), LoginResultCallback { @@ -21,11 +32,15 @@ class LoginActivity : AppCompatActivity(), LoginResultCallback { retrofit.login(email, password, this) } + private lateinit var connectivityObserver: ConnectivityObserver + private var networkState: ConnectivityObserver.NetworkState? = null + override fun onSuccess(loginResponse: com.example.abe.data.network.LoginResponse) { // Handle successful login println("Login successful: $loginResponse") - val sharedPref = getSharedPreferences(getString(R.string.preference_file_key), Context.MODE_PRIVATE) + val sharedPref = + getSharedPreferences(getString(R.string.preference_file_key), Context.MODE_PRIVATE) with(sharedPref.edit()) { putString("login_token", loginResponse.token) putString("user", email) @@ -51,11 +66,39 @@ class LoginActivity : AppCompatActivity(), LoginResultCallback { val view = binding.root setContentView(view) + connectivityObserver = NetworkConnectivityObserver(applicationContext) + connectivityObserver.observe().onEach { + Log.v("abecekut", "Status is $it") + networkState = it + if (it == ConnectivityObserver.NetworkState.UNAVAILABLE || it == ConnectivityObserver.NetworkState.LOST) { + runOnUiThread { + val builder: AlertDialog.Builder = AlertDialog.Builder(this@LoginActivity) + builder + .setMessage("We are having trouble connecting you to the internet") + .setTitle("No Connection") + .setPositiveButton("OK") { _, _ -> } + + val dialog: AlertDialog = builder.create() + dialog.show() + } + } + }.launchIn(lifecycleScope) + binding.btnSignIn.setOnClickListener { email = binding.emailInput.text.toString() val password: String = binding.passwordInput.text.toString() - attemptLogin(email, password) + if (!isConnected(networkState)) { + binding.loginLayout.visibility = View.GONE + binding.noNetworkLayout.visibility = View.VISIBLE + } else { + attemptLogin(email, password) + } + } + + binding.btnTryAgain.setOnClickListener { + binding.noNetworkLayout.visibility = View.GONE + binding.loginLayout.visibility = View.VISIBLE } } } diff --git a/app/src/main/java/com/example/abe/ui/transactions/TransactionFragment.kt b/app/src/main/java/com/example/abe/ui/transactions/TransactionFragment.kt index 9f9b8eb63407d44195b0fb75ca7353e4511dfe80..f36b9313b81a91aa5b801f07c32b7ec1f722410e 100644 --- a/app/src/main/java/com/example/abe/ui/transactions/TransactionFragment.kt +++ b/app/src/main/java/com/example/abe/ui/transactions/TransactionFragment.kt @@ -42,7 +42,7 @@ class TransactionFragment : Fragment() { ): View { _binding = FragmentTransactionsBinding.inflate(inflater, container, false) - val transactionsAdapter = TransactionsAdapter(listener) + val transactionsAdapter = TransactionsAdapter(listener, requireContext()) binding.rvTransactions.adapter = transactionsAdapter binding.rvTransactions.layoutManager = LinearLayoutManager(context) diff --git a/app/src/main/java/com/example/abe/ui/transactions/TransactionsAdapter.kt b/app/src/main/java/com/example/abe/ui/transactions/TransactionsAdapter.kt index da1ba890916ffe5f792b599e2df53560dfe18d83..884d911cbddfa53b502ca55613d47fd1ed5ddb2c 100644 --- a/app/src/main/java/com/example/abe/ui/transactions/TransactionsAdapter.kt +++ b/app/src/main/java/com/example/abe/ui/transactions/TransactionsAdapter.kt @@ -1,6 +1,6 @@ package com.example.abe.ui.transactions -import android.content.Intent +import android.content.Context import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -13,11 +13,10 @@ import androidx.recyclerview.widget.RecyclerView import com.example.abe.R import com.example.abe.data.Transaction import com.example.abe.domain.FormatCurrencyUseCase -import com.example.abe.ui.form_transaction.FormTransaction import java.text.SimpleDateFormat import java.util.Locale -class TransactionsAdapter(private val itemClickListener: TransactionFragment.ItemClickListener): ListAdapter<Transaction, TransactionsAdapter.TransactionViewHolder>(TransactionComparator()) { +class TransactionsAdapter(private val itemClickListener: TransactionFragment.ItemClickListener, private val context: Context): ListAdapter<Transaction, TransactionsAdapter.TransactionViewHolder>(TransactionComparator()) { class TransactionViewHolder(val view: View): RecyclerView.ViewHolder(view) { val clImageContainer: ConstraintLayout val ivTrxIcon: ImageView @@ -55,15 +54,15 @@ class TransactionsAdapter(private val itemClickListener: TransactionFragment.Ite override fun onBindViewHolder(holder: TransactionViewHolder, position: Int) { with(holder) { -// TODO Set color from theme -// clImageContainer.background = val trx = getItem(position) - if (!trx.isExpense) - ivTrxIcon.setImageResource(R.drawable.ic_circle_arrow_up) + if (!trx.isExpense) { + clImageContainer.setBackgroundColor(context.getColor(R.color.secondary)) + ivTrxIcon.setImageResource(R.drawable.ic_circle_arrow_down) + tvAmount.setTextColor(context.getColor(R.color.success)) + } tvTrxTitle.text = trx.title -// TODO location tvLocation.text = trx.location tvDate.text = SimpleDateFormat("d MMM yyyy" , Locale.ENGLISH).format(trx.timestamp) @@ -73,9 +72,6 @@ class TransactionsAdapter(private val itemClickListener: TransactionFragment.Ite tvAmount.text = amountText view.setOnClickListener { -// val intent = Intent(it.context, FormTransaction::class.java) -// intent.putExtra("id", trx.id.toString()) -// it.context.startActivity(intent) itemClickListener.onItemClicked(trx.id) } } diff --git a/app/src/main/java/com/example/abe/utils/Utils.kt b/app/src/main/java/com/example/abe/utils/Utils.kt new file mode 100644 index 0000000000000000000000000000000000000000..d68b03eaef07b4a4338b6459ba5c344cfe3adaaa --- /dev/null +++ b/app/src/main/java/com/example/abe/utils/Utils.kt @@ -0,0 +1,7 @@ +package com.example.abe.utils + +import com.example.abe.connection.ConnectivityObserver + +fun isConnected(networkState: ConnectivityObserver.NetworkState?): Boolean { + return (networkState != null && (networkState == ConnectivityObserver.NetworkState.AVAILABLE || networkState == ConnectivityObserver.NetworkState.LOSING)) +} diff --git a/app/src/main/res/drawable-anydpi/ic_location.xml b/app/src/main/res/drawable-anydpi/ic_location.xml deleted file mode 100644 index b9d9d8ed33a1ace67d33c0617f89297bb6cafa9d..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable-anydpi/ic_location.xml +++ /dev/null @@ -1,14 +0,0 @@ -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24" - android:viewportHeight="24" - android:tint="#333333" - android:alpha="0.6"> - <path - android:fillColor="@android:color/white" - android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13c0,-3.87 -3.13,-7 -7,-7zM7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,2.88 -2.88,7.19 -5,9.88C9.92,16.21 7,11.85 7,9z"/> - <path - android:fillColor="@android:color/white" - android:pathData="M12,9m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/> -</vector> diff --git a/app/src/main/res/drawable-hdpi/ic_circle_arrow_down.png b/app/src/main/res/drawable-hdpi/ic_circle_arrow_down.png deleted file mode 100644 index 980f177e72d69141cd8ae84efb8fff90b2a0988c..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/ic_circle_arrow_down.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_circle_arrow_up.png b/app/src/main/res/drawable-hdpi/ic_circle_arrow_up.png deleted file mode 100644 index 2df26c358a169facb16be6433616d72a96901080..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/ic_circle_arrow_up.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_location.png b/app/src/main/res/drawable-hdpi/ic_location.png deleted file mode 100644 index bca6e8e9a5f2b25f59b4027ab85258384717852d..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-hdpi/ic_location.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_circle_arrow_down.png b/app/src/main/res/drawable-mdpi/ic_circle_arrow_down.png deleted file mode 100644 index ed12d153b6901c4fa2b5f4369f2015fcf88c85d9..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-mdpi/ic_circle_arrow_down.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_circle_arrow_up.png b/app/src/main/res/drawable-mdpi/ic_circle_arrow_up.png deleted file mode 100644 index 1f66acd65c8875497d8d3ca2219671c4ccbffeac..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-mdpi/ic_circle_arrow_up.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_location.png b/app/src/main/res/drawable-mdpi/ic_location.png deleted file mode 100644 index 8c8b1ae762f8faf4803ea8f4d3c0c39745f467a2..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-mdpi/ic_location.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_circle_arrow_down.png b/app/src/main/res/drawable-xhdpi/ic_circle_arrow_down.png deleted file mode 100644 index 697175ebd1fee62e95deb3c7eb111f47148257b8..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_circle_arrow_down.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_circle_arrow_up.png b/app/src/main/res/drawable-xhdpi/ic_circle_arrow_up.png deleted file mode 100644 index 967c678704cce4b2ada24dd2f98b4d7402d7e8c1..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_circle_arrow_up.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_location.png b/app/src/main/res/drawable-xhdpi/ic_location.png deleted file mode 100644 index a2d7b570471f1ac5db73861a32ee5c9d4f20be9b..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_location.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_circle_arrow_down.png b/app/src/main/res/drawable-xxhdpi/ic_circle_arrow_down.png deleted file mode 100644 index c074b4059221244165a67f93c5cf119e7f575f72..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_circle_arrow_down.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_circle_arrow_up.png b/app/src/main/res/drawable-xxhdpi/ic_circle_arrow_up.png deleted file mode 100644 index 8c9aa70c7003451884b8a360b50b18c91c31c789..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_circle_arrow_up.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_location.png b/app/src/main/res/drawable-xxhdpi/ic_location.png deleted file mode 100644 index c7de6afd707c828c21747c1b2a6a158485fe6ace..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_location.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_circle_arrow_down.png b/app/src/main/res/drawable-xxxhdpi/ic_circle_arrow_down.png deleted file mode 100644 index 0c7f7de74066376d5fcf5967a5f084c34e413aa0..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_circle_arrow_down.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_circle_arrow_up.png b/app/src/main/res/drawable-xxxhdpi/ic_circle_arrow_up.png deleted file mode 100644 index fd1bd6ebaecee1a2dfe9cb60b588f54679b3fd2a..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_circle_arrow_up.png and /dev/null differ diff --git a/app/src/main/res/drawable/bg_transaction_row_item.xml b/app/src/main/res/drawable/bg_transaction_row_item.xml new file mode 100644 index 0000000000000000000000000000000000000000..27f44b0a5f89293b2adb188be77cea1f338c3c1b --- /dev/null +++ b/app/src/main/res/drawable/bg_transaction_row_item.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@color/grayLight"/> + <corners android:radius="12dp"/> +</shape> \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_circle_arrow_down.xml b/app/src/main/res/drawable/ic_circle_arrow_down.xml new file mode 100644 index 0000000000000000000000000000000000000000..2289e2d2d12db78041730283cd9928617b443039 --- /dev/null +++ b/app/src/main/res/drawable/ic_circle_arrow_down.xml @@ -0,0 +1,27 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="32dp" + android:height="32dp" + android:viewportWidth="32" + android:viewportHeight="32"> + <path + android:pathData="M16,29.333C23.364,29.333 29.333,23.364 29.333,16C29.333,8.636 23.364,2.667 16,2.667C8.636,2.667 2.667,8.636 2.667,16C2.667,23.364 8.636,29.333 16,29.333Z" + android:strokeLineJoin="round" + android:strokeWidth="2" + android:fillColor="#00000000" + android:strokeColor="#ffffff" + android:strokeLineCap="round"/> + <path + android:pathData="M16,10.667V21.333" + android:strokeLineJoin="round" + android:strokeWidth="2" + android:fillColor="#00000000" + android:strokeColor="#ffffff" + android:strokeLineCap="round"/> + <path + android:pathData="M10.667,16L16,21.333L21.333,16" + android:strokeLineJoin="round" + android:strokeWidth="2" + android:fillColor="#00000000" + android:strokeColor="#ffffff" + android:strokeLineCap="round"/> +</vector> diff --git a/app/src/main/res/drawable/ic_circle_arrow_up.xml b/app/src/main/res/drawable/ic_circle_arrow_up.xml new file mode 100644 index 0000000000000000000000000000000000000000..0e1bc5f0552e24f2a132f09facfe2bbe78f9df26 --- /dev/null +++ b/app/src/main/res/drawable/ic_circle_arrow_up.xml @@ -0,0 +1,27 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="32dp" + android:height="32dp" + android:viewportWidth="32" + android:viewportHeight="32"> + <path + android:pathData="M16,29.333C23.364,29.333 29.333,23.364 29.333,16C29.333,8.636 23.364,2.667 16,2.667C8.636,2.667 2.667,8.636 2.667,16C2.667,23.364 8.636,29.333 16,29.333Z" + android:strokeLineJoin="round" + android:strokeWidth="2.66667" + android:fillColor="#00000000" + android:strokeColor="#ffffff" + android:strokeLineCap="round"/> + <path + android:pathData="M21.333,16L16,10.667L10.667,16" + android:strokeLineJoin="round" + android:strokeWidth="2.66667" + android:fillColor="#00000000" + android:strokeColor="#ffffff" + android:strokeLineCap="round"/> + <path + android:pathData="M16,21.333V10.667" + android:strokeLineJoin="round" + android:strokeWidth="2.66667" + android:fillColor="#00000000" + android:strokeColor="#ffffff" + android:strokeLineCap="round"/> +</vector> diff --git a/app/src/main/res/drawable/ic_map_pin.xml b/app/src/main/res/drawable/ic_map_pin.xml new file mode 100644 index 0000000000000000000000000000000000000000..1d355d2e9e6e65e084f670a86cd0536d65f138ed --- /dev/null +++ b/app/src/main/res/drawable/ic_map_pin.xml @@ -0,0 +1,20 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="12dp" + android:height="12dp" + android:viewportWidth="12" + android:viewportHeight="12"> + <path + android:strokeWidth="1" + android:pathData="M10,5C10,8 6,11 6,11C6,11 2,8 2,5C2,3.939 2.421,2.921 3.172,2.171C3.922,1.421 4.939,1 6,1C7.061,1 8.078,1.421 8.828,2.171C9.579,2.921 10,3.939 10,5Z" + android:strokeLineJoin="round" + android:fillColor="#00000000" + android:strokeColor="#8346AA" + android:strokeLineCap="round"/> + <path + android:strokeWidth="1" + android:pathData="M6,6.5C6.828,6.5 7.5,5.829 7.5,5C7.5,4.172 6.828,3.5 6,3.5C5.172,3.5 4.5,4.172 4.5,5C4.5,5.829 5.172,6.5 6,6.5Z" + android:strokeLineJoin="round" + android:fillColor="#00000000" + android:strokeColor="#8346AA" + android:strokeLineCap="round"/> +</vector> diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index ac3598da695e7e684b840dfb9651f3ea3e78925e..48f3fa71a778687cb4c4e7d311426835aceebaa6 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -7,87 +7,143 @@ android:backgroundTint="#9759C4" tools:context=".ui.login.LoginActivity"> - <EditText - android:id="@+id/emailInput" - android:layout_width="300dp" + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/loginLayout" + android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginBottom="16dp" - android:ems="10" - android:hint="Email" - android:inputType="textEmailAddress" - android:outlineAmbientShadowColor="#000000" - android:outlineProvider="background" android:visibility="visible" - app:layout_constraintBottom_toTopOf="@+id/passwordInput" + app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/appName" - app:layout_constraintVertical_bias="0.5" - app:layout_constraintVertical_chainStyle="packed" - tools:visibility="visible" /> + app:layout_constraintTop_toTopOf="parent"> - <EditText - android:id="@+id/passwordInput" - android:layout_width="300dp" - android:layout_height="wrap_content" - android:ems="10" - android:hint="Password" - android:inputType="textPassword" - app:layout_constraintBottom_toTopOf="@+id/btnSignIn" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintHorizontal_bias="0.5" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/emailInput" - app:layout_constraintVertical_bias="0.5" /> + <EditText + android:id="@+id/emailInput" + android:layout_width="300dp" + android:layout_height="wrap_content" + android:layout_marginBottom="16dp" + android:ems="10" + android:hint="Email" + android:inputType="textEmailAddress" + android:outlineAmbientShadowColor="#000000" + android:outlineProvider="background" + app:layout_constraintBottom_toTopOf="@+id/passwordInput" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.5" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/appName" + app:layout_constraintVertical_bias="0.5" + app:layout_constraintVertical_chainStyle="packed" /> - <Button - android:id="@+id/btnSignIn" - android:layout_width="300dp" - android:layout_height="wrap_content" - android:layout_marginTop="36dp" - android:background="#9759C4" - android:clickable="true" - android:text="Sign in" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintHorizontal_bias="0.5" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/passwordInput" - app:layout_constraintVertical_bias="0.5" /> - <TextView - android:id="@+id/welcomeText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginBottom="8dp" - android:fontFamily="@font/roboto_medium" - android:text="Welcome back to" - android:textColor="#000000" - android:textSize="20sp" - app:layout_constraintBottom_toTopOf="@+id/appName" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintHorizontal_bias="0.5" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintVertical_bias="0.5" - app:layout_constraintVertical_chainStyle="packed" /> + <EditText + android:id="@+id/passwordInput" + android:layout_width="300dp" + android:layout_height="wrap_content" + android:ems="10" + android:hint="Password" + android:inputType="textPassword" + app:layout_constraintBottom_toTopOf="@+id/btnSignIn" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.5" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/emailInput" + app:layout_constraintVertical_bias="0.5" /> + + <Button + android:id="@+id/btnSignIn" + android:layout_width="300dp" + android:layout_height="wrap_content" + android:layout_marginTop="36dp" + android:background="#9759C4" + android:clickable="true" + android:text="Sign in" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.5" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/passwordInput" + app:layout_constraintVertical_bias="0.5" /> + + <TextView + android:id="@+id/welcomeText" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginBottom="8dp" + android:fontFamily="@font/roboto_medium" + android:text="Welcome back to" + android:textColor="#000000" + android:textSize="20sp" + app:layout_constraintBottom_toTopOf="@+id/appName" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.5" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0.5" + app:layout_constraintVertical_chainStyle="packed" /> - <TextView - android:id="@+id/appName" + <TextView + android:id="@+id/appName" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:layout_marginBottom="64dp" + android:fontFamily="@font/carter_one" + android:text="Bondoman" + android:textColor="#9759C4" + android:textSize="24sp" + android:textStyle="bold" + app:layout_constraintBottom_toTopOf="@+id/emailInput" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.5" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/welcomeText" + app:layout_constraintVertical_bias="0.5" /> + </androidx.constraintlayout.widget.ConstraintLayout> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/noNetworkLayout" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginTop="8dp" - android:layout_marginBottom="64dp" - android:fontFamily="@font/carter_one" - android:text="Bondoman" - android:textColor="#9759C4" - android:textSize="24sp" - android:textStyle="bold" - app:layout_constraintBottom_toTopOf="@+id/emailInput" + android:visibility="gone" + app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/welcomeText" - app:layout_constraintVertical_bias="0.5" /> + app:layout_constraintTop_toTopOf="parent"> + + <ImageView + android:id="@+id/ivTrxIcon" + android:layout_width="400dp" + android:layout_height="350dp" + android:src="@mipmap/no_network_foreground" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/textView2" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginHorizontal="20dp" + android:text="@string/failed_connect_msg" + android:textAlignment="center" + android:textSize="16sp" + android:textStyle="bold" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/ivTrxIcon" /> + + <Button + android:id="@+id/btnTryAgain" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/try_again" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/textView2" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + + </androidx.constraintlayout.widget.ConstraintLayout> \ 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 index 06ea6cae22113f243efe317f984f7742418737e8..78cfef8004e741d5a24edec4cdf0db058a249561 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -3,8 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/container" android:layout_width="match_parent" - android:layout_height="match_parent" - android:paddingTop="?attr/actionBarSize"> + android:layout_height="match_parent"> <com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/nav_view" @@ -22,9 +21,9 @@ android:id="@+id/nav_host_fragment_activity_main" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="match_parent" - android:layout_height="match_parent" + android:layout_height="0dp" app:defaultNavHost="true" - app:layout_constraintBottom_toTopOf="@id/nav_view" + app:layout_constraintBottom_toTopOf="@+id/nav_view" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" diff --git a/app/src/main/res/layout/fragment_form_transaction.xml b/app/src/main/res/layout/fragment_form_transaction.xml index b3c08de536f52f69764affdbd37965f40e197c93..6bec0c5bd2b7036ce7e296316aa728af398e5ba6 100644 --- a/app/src/main/res/layout/fragment_form_transaction.xml +++ b/app/src/main/res/layout/fragment_form_transaction.xml @@ -75,33 +75,49 @@ android:id="@+id/categoryAutocomplete" android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@={viewModel.category}" android:inputType="none" - android:labelFor="@+id/formCategoryContainer" /> + android:labelFor="@+id/formCategoryContainer" + android:text="@={viewModel.category}" /> </com.google.android.material.textfield.TextInputLayout> + <Button + android:id="@+id/btnOpenMap" + android:minWidth="0dp" + android:minHeight="0dp" + android:layout_width="wrap_content" + android:layout_height="0dp" + android:paddingTop="1dp" + android:paddingBottom="1dp" + android:layout_marginTop="8dp" + android:text="Open in Map" + android:textColor="@color/primary" + android:background="@android:color/transparent" + android:textSize="14sp" + android:textStyle="bold" + app:layout_constraintEnd_toEndOf="@+id/formCategoryContainer" + app:layout_constraintTop_toBottomOf="@+id/formCategoryContainer" /> + <com.google.android.material.textfield.TextInputLayout android:id="@+id/formLocationContainer" style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="20dp" - android:layout_marginTop="5dp" app:helperTextTextColor="@color/destructive" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/formCategoryContainer"> + app:layout_constraintTop_toBottomOf="@id/btnOpenMap"> <com.google.android.material.textfield.TextInputEditText android:id="@+id/formLocationEditText" android:layout_width="match_parent" android:layout_height="match_parent" - android:text="@={viewModel.location}" android:hint="Location" android:inputType="text" - android:lines="1" /> + android:lines="1" + android:text="@={viewModel.location}" /> </com.google.android.material.textfield.TextInputLayout> diff --git a/app/src/main/res/layout/fragment_transactions.xml b/app/src/main/res/layout/fragment_transactions.xml index 1cfe6a3db8d58e63a4de6a25e5d047e743a64e1f..ed123034afaa7d6e5684acfaa00b959d5d42d63c 100644 --- a/app/src/main/res/layout/fragment_transactions.xml +++ b/app/src/main/res/layout/fragment_transactions.xml @@ -9,7 +9,9 @@ <androidx.recyclerview.widget.RecyclerView android:id="@+id/rvTransactions" android:layout_width="match_parent" - android:layout_height="0dp" + android:layout_height="match_parent" + android:padding="12dp" + android:clipToPadding="false" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" diff --git a/app/src/main/res/layout/item_transaction_row_item.xml b/app/src/main/res/layout/item_transaction_row_item.xml index 36c46a0322b5a372fb07273a036e8120021d6a7c..ce5ea19f43f6515fea918deb2430e75f5374bc41 100644 --- a/app/src/main/res/layout/item_transaction_row_item.xml +++ b/app/src/main/res/layout/item_transaction_row_item.xml @@ -1,11 +1,12 @@ <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" - xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="100dp" android:paddingLeft="16dp" android:paddingRight="16dp" + android:background="@drawable/bg_transaction_row_item" + android:layout_marginBottom="12dp" > <!-- TODO background colors & try clipping for rounded corner--> @@ -21,7 +22,7 @@ android:id="@+id/ivTrxIcon" android:layout_width="32dp" android:layout_height="32dp" - android:src="@drawable/ic_circle_arrow_down" + android:src="@drawable/ic_circle_arrow_up" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -29,10 +30,11 @@ </androidx.constraintlayout.widget.ConstraintLayout> <androidx.constraintlayout.widget.ConstraintLayout - android:layout_width="wrap_content" + android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="12dp" app:layout_constraintBottom_toBottomOf="@+id/clImageContainer" + app:layout_constraintEnd_toStartOf="@+id/tvAmount" app:layout_constraintStart_toEndOf="@+id/clImageContainer" app:layout_constraintTop_toTopOf="@+id/clImageContainer"> @@ -41,6 +43,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Shopping Spree" + android:textColor="@color/black" android:textSize="16sp" android:textStyle="bold" app:layout_constraintStart_toStartOf="parent" @@ -48,19 +51,23 @@ <ImageView android:id="@+id/ivLocation" - android:layout_width="10sp" - android:layout_height="10sp" + android:layout_width="12sp" + android:layout_height="12sp" app:layout_constraintBottom_toBottomOf="@+id/tvLocation" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/tvLocation" - app:srcCompat="@drawable/ic_location" /> + app:srcCompat="@drawable/ic_map_pin" /> <TextView android:id="@+id/tvLocation" - android:layout_width="wrap_content" + android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="4dp" + android:ellipsize="end" + android:maxLines="2" android:text="Shopee" + android:textColor="@color/primary" + app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/ivLocation" app:layout_constraintTop_toBottomOf="@+id/tvTrxTitle" /> @@ -69,6 +76,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="3 Mar 2024" + android:textColor="@color/grayDark" android:textSize="12sp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tvLocation" /> @@ -80,6 +88,8 @@ android:layout_height="wrap_content" android:text="-Rp350.000" android:textStyle="bold" + android:textSize="16sp" + android:textColor="@color/destructive" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" diff --git a/app/src/main/res/mipmap-hdpi/no_network_foreground.webp b/app/src/main/res/mipmap-hdpi/no_network_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..146477e4daed7e4d42df864763d93dea4a21e1bf Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/no_network_foreground.webp differ diff --git a/app/src/main/res/mipmap-mdpi/no_network_foreground.webp b/app/src/main/res/mipmap-mdpi/no_network_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..50b1eadd920f2070aa96dbb6878c12178537b6b8 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/no_network_foreground.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/no_network_foreground.webp b/app/src/main/res/mipmap-xhdpi/no_network_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..d88f22adbe89b8b19c3f54d6deacc1b835930aac Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/no_network_foreground.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/no_network_foreground.webp b/app/src/main/res/mipmap-xxhdpi/no_network_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..4859633958ea9fd9290ae494744a54b4b1e7409c Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/no_network_foreground.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/no_network_foreground.webp b/app/src/main/res/mipmap-xxxhdpi/no_network_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..e6c5741b8e84a8463cf99b886c0f57d2e097660b Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/no_network_foreground.webp differ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 27b03fd014a2bff83443fc7c5d0439313bba6423..cb0e255805159c00e1f22d060c974c2ef308f783 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -9,6 +9,8 @@ <string name="save">Save</string> <string name="delete">Delete</string> <string name="preference_file_key">com.example.ABE.PREFERENCE_FILE_KEY</string> + <string name="failed_connect_msg">Failed to connect to the server. Please check your internet connection.</string> + <string name="try_again">Try Again</string> <string-array name="Categories"> <item>Income</item>