summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2019-09-02 10:50:45 +0200
committerFlorian Dold <florian.dold@gmail.com>2019-09-02 10:50:45 +0200
commit26228306686bb37c18a48b25eba59c354379150c (patch)
treeef21e7cddcb48d2a1554579b9255026ae83de33f
parentd783859b7928566090c88be05c6cf3871de6fbf2 (diff)
downloadmerchant-terminal-android-26228306686bb37c18a48b25eba59c354379150c.tar.gz
merchant-terminal-android-26228306686bb37c18a48b25eba59c354379150c.tar.bz2
merchant-terminal-android-26228306686bb37c18a48b25eba59c354379150c.zip
implement backend settings
-rw-r--r--app/build.gradle2
-rw-r--r--app/src/main/java/net/taler/merchantpos/Amount.kt29
-rw-r--r--app/src/main/java/net/taler/merchantpos/CreatePayment.kt9
-rw-r--r--app/src/main/java/net/taler/merchantpos/MainActivity.kt10
-rw-r--r--app/src/main/java/net/taler/merchantpos/MerchantConfig.kt7
-rw-r--r--app/src/main/java/net/taler/merchantpos/MerchantHistory.kt138
-rw-r--r--app/src/main/java/net/taler/merchantpos/MerchantSettings.kt111
-rw-r--r--app/src/main/res/layout/fragment_create_payment.xml2
-rw-r--r--app/src/main/res/layout/fragment_merchant_history.xml33
-rw-r--r--app/src/main/res/layout/fragment_merchant_settings.xml93
-rw-r--r--app/src/main/res/layout/history_row.xml79
11 files changed, 457 insertions, 56 deletions
diff --git a/app/build.gradle b/app/build.gradle
index 0f36545..c1fc89b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -64,6 +64,8 @@ dependencies {
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
+ implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
+
// JSON literals and parsing
implementation 'com.beust:klaxon:5.0.11'
}
diff --git a/app/src/main/java/net/taler/merchantpos/Amount.kt b/app/src/main/java/net/taler/merchantpos/Amount.kt
new file mode 100644
index 0000000..15cadf4
--- /dev/null
+++ b/app/src/main/java/net/taler/merchantpos/Amount.kt
@@ -0,0 +1,29 @@
+package net.taler.merchantpos
+
+import org.json.JSONObject
+
+data class Amount(val currency: String, val amount: String) {
+ fun isZero(): Boolean {
+ return amount.toDouble() == 0.0
+ }
+
+ companion object {
+ const val FRACTIONAL_BASE = 1e8;
+ fun fromJson(jsonAmount: JSONObject): Amount {
+ val amountCurrency = jsonAmount.getString("currency")
+ val amountValue = jsonAmount.getString("value")
+ val amountFraction = jsonAmount.getString("fraction")
+ val amountIntValue = Integer.parseInt(amountValue)
+ val amountIntFraction = Integer.parseInt(amountFraction)
+ return Amount(
+ amountCurrency,
+ (amountIntValue + amountIntFraction / FRACTIONAL_BASE).toString()
+ )
+ }
+
+ fun fromString(strAmount: String): Amount {
+ val components = strAmount.split(":")
+ return Amount(components[0], components[1])
+ }
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/net/taler/merchantpos/CreatePayment.kt b/app/src/main/java/net/taler/merchantpos/CreatePayment.kt
index c6a8066..83dbed8 100644
--- a/app/src/main/java/net/taler/merchantpos/CreatePayment.kt
+++ b/app/src/main/java/net/taler/merchantpos/CreatePayment.kt
@@ -1,11 +1,13 @@
package net.taler.merchantpos
+import android.annotation.SuppressLint
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.EditText
+import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProviders
import androidx.navigation.fragment.findNavController
@@ -36,6 +38,10 @@ class CreatePayment : Fragment() {
override fun onResume() {
super.onResume()
this.paused = false
+
+ val textView = view!!.findViewById<TextView>(R.id.text_create_payment_amount_label)
+ @SuppressLint("SetTextI18n")
+ textView.text = "Amount (${model.merchantConfig!!.currency})"
}
override fun onCreate(savedInstanceState: Bundle?) {
@@ -50,7 +56,7 @@ class CreatePayment : Fragment() {
private fun onRequestPayment() {
val amountValStr = activity!!.findViewById<EditText>(R.id.edit_payment_amount).text
- val amount = "TESTKUDOS:${amountValStr}"
+ val amount = "${model.merchantConfig!!.currency}:${amountValStr}"
model.activeAmount = amount
model.activeSubject = activity!!.findViewById<EditText>(R.id.edit_payment_subject).text
@@ -117,6 +123,7 @@ class CreatePayment : Fragment() {
requestPaymentButton.setOnClickListener {
onRequestPayment()
}
+
return view
}
diff --git a/app/src/main/java/net/taler/merchantpos/MainActivity.kt b/app/src/main/java/net/taler/merchantpos/MainActivity.kt
index e8e9a2a..7c8330a 100644
--- a/app/src/main/java/net/taler/merchantpos/MainActivity.kt
+++ b/app/src/main/java/net/taler/merchantpos/MainActivity.kt
@@ -1,5 +1,6 @@
package net.taler.merchantpos
+import android.content.Context
import android.nfc.NfcAdapter
import android.nfc.Tag
import android.nfc.tech.IsoDep
@@ -276,9 +277,16 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
findViewById<Toolbar>(R.id.toolbar)
.setupWithNavController(navController, appBarConfiguration)
+ val prefs = getSharedPreferences("taler-merchant-terminal", Context.MODE_PRIVATE)
+
+ val baseUrl = prefs.getString("merchantBackendUrl", "https://backend.test.taler.net")
+ val instance = prefs.getString("merchantBackendInstance", "default")
+ val apiKey = prefs.getString("merchantBackendApiKey", "sandbox")
+ val currency = prefs.getString("merchantBackendCurrency", "TESTKUDOS")
+
model = ViewModelProviders.of(this)[PosTerminalViewModel::class.java]
model.merchantConfig =
- MerchantConfig("https://backend.test.taler.net", "default", "sandbox")
+ MerchantConfig(baseUrl!!, instance!!, apiKey!!, currency!!)
}
diff --git a/app/src/main/java/net/taler/merchantpos/MerchantConfig.kt b/app/src/main/java/net/taler/merchantpos/MerchantConfig.kt
index 3e043a0..626d60b 100644
--- a/app/src/main/java/net/taler/merchantpos/MerchantConfig.kt
+++ b/app/src/main/java/net/taler/merchantpos/MerchantConfig.kt
@@ -2,7 +2,12 @@ package net.taler.merchantpos
import android.net.Uri
-data class MerchantConfig(val baseUrl: String, val instance: String, val apiKey: String) {
+data class MerchantConfig(
+ val baseUrl: String,
+ val instance: String,
+ val apiKey: String,
+ val currency: String
+) {
fun urlFor(endpoint: String, params: Map<String, String>?): String {
val uriBuilder = Uri.parse(baseUrl).buildUpon()
uriBuilder.appendPath(endpoint)
diff --git a/app/src/main/java/net/taler/merchantpos/MerchantHistory.kt b/app/src/main/java/net/taler/merchantpos/MerchantHistory.kt
index c3bab06..b79f836 100644
--- a/app/src/main/java/net/taler/merchantpos/MerchantHistory.kt
+++ b/app/src/main/java/net/taler/merchantpos/MerchantHistory.kt
@@ -1,23 +1,48 @@
package net.taler.merchantpos
+import android.annotation.SuppressLint
import android.os.Bundle
+import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
+import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
+import com.android.volley.Request
import com.android.volley.RequestQueue
+import com.android.volley.Response
+import com.android.volley.VolleyError
import com.android.volley.toolbox.Volley
+import com.google.android.material.snackbar.Snackbar
+import org.json.JSONObject
+import java.time.Instant
+import java.time.ZoneId
+import java.time.format.DateTimeFormatter
+import java.time.format.FormatStyle
+import java.util.*
-class MyAdapter(private val myDataset: Array<String>) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
+
+
+data class HistoryItem(
+ val orderId: String,
+ val amount: Amount,
+ val summary: String,
+ val timestamp: Instant
+)
+
+class MyAdapter(private var myDataset: List<HistoryItem>) :
+ RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
- val textView = LayoutInflater.from(parent.context).inflate(R.layout.history_row, parent, false)
- return MyViewHolder(textView as TextView)
+ val view =
+ LayoutInflater.from(parent.context).inflate(R.layout.history_row, parent, false)
+ return MyViewHolder(view)
}
override fun getItemCount(): Int {
@@ -25,24 +50,47 @@ class MyAdapter(private val myDataset: Array<String>) : RecyclerView.Adapter<MyA
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
- holder.textView.text = myDataset[position]
+ val item = myDataset[position]
+ val summaryTextView = holder.rowView.findViewById<TextView>(R.id.text_history_summary)
+ summaryTextView.text = myDataset[position].summary
+
+ val amount = myDataset[position].amount
+ val amountTextView = holder.rowView.findViewById<TextView>(R.id.text_history_amount)
+ @SuppressLint("SetTextI18n")
+ amountTextView.text = "${amount.amount} ${amount.currency}"
+
+ val formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT)
+ .withLocale(Locale.UK)
+ .withZone(ZoneId.systemDefault())
+ val timestampTextView = holder.rowView.findViewById<TextView>(R.id.text_history_time)
+ timestampTextView.text = formatter.format(item.timestamp)
+
+ val orderIdTextView = holder.rowView.findViewById<TextView>(R.id.text_history_order_id)
+ orderIdTextView.text = item.orderId
+ }
+
+ fun setData(dataset: List<HistoryItem>) {
+ this.myDataset = dataset
+ this.notifyDataSetChanged()
}
- class MyViewHolder(val textView: TextView) : RecyclerView.ViewHolder(textView)
+ class MyViewHolder(val rowView: View) : RecyclerView.ViewHolder(rowView)
+}
+
+fun parseTalerTimestamp(s: String): Instant {
+ return Instant.ofEpochSecond(s.substringAfterLast('(').substringBeforeLast(')').toLong())
}
/**
- * A simple [Fragment] subclass.
- * Activities that contain this fragment must implement the
- * [MerchantHistory.OnFragmentInteractionListener] interface
- * to handle interaction events.
- * Use the [MerchantHistory.newInstance] factory method to
- * create an instance of this fragment.
- *
+ * Fragment to display the merchant's payment history,
+ * received from the backend.
*/
class MerchantHistory : Fragment() {
private lateinit var queue: RequestQueue
private lateinit var model: PosTerminalViewModel
+ private val historyListAdapter = MyAdapter(listOf())
+
+ private val isLoading = MutableLiveData<Boolean>().apply { value = false }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -54,6 +102,48 @@ class MerchantHistory : Fragment() {
queue = Volley.newRequestQueue(context)
}
+ private fun onNetworkError(volleyError: VolleyError?) {
+ this.isLoading.value = false
+ val mySnackbar = Snackbar.make(view!!, "Network Error", Snackbar.LENGTH_SHORT)
+ mySnackbar.show()
+ }
+
+ private fun onHistoryResponse(body: JSONObject) {
+ this.isLoading.value = false
+ Log.v(TAG, "got history response ${body}")
+ val data = arrayListOf<HistoryItem>()
+ val historyJson = body.getJSONArray("history")
+ for (i in 0 until historyJson.length()) {
+ val item = historyJson.getJSONObject(i)
+ val orderId = item.getString("order_id")
+ val summary = item.getString("summary")
+ val timestampStr = item.getString("timestamp")
+ val timestamp = parseTalerTimestamp(timestampStr)
+ val amount = Amount.fromString(item.getString("amount"))
+ data.add(HistoryItem(orderId, amount, summary, timestamp))
+ }
+ historyListAdapter.setData(data)
+ }
+
+ private fun fetchHistory() {
+ isLoading.value = true
+ val instance = model.merchantConfig!!.instance
+ val req = MerchantInternalRequest(
+ Request.Method.GET,
+ model.merchantConfig!!,
+ "history",
+ mapOf("instance" to instance),
+ null,
+ Response.Listener { onHistoryResponse(it) },
+ Response.ErrorListener { onNetworkError(it) })
+ queue.add(req)
+ }
+
+ override fun onResume() {
+ super.onResume()
+ fetchHistory()
+ }
+
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
@@ -62,16 +152,28 @@ class MerchantHistory : Fragment() {
val myItemDecoration = DividerItemDecoration(context, myLayoutManager.orientation)
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_merchant_history, container, false)
- val myList = ArrayList<String>()
- for (i in 0..100) {
- myList.add("Element $i")
- }
- val myArray: Array<String> = myList.toTypedArray()
view.findViewById<RecyclerView>(R.id.list_history).apply {
layoutManager = myLayoutManager
- adapter = MyAdapter(myArray)
+ adapter = historyListAdapter
addItemDecoration(myItemDecoration)
}
+
+ val refreshLayout = view.findViewById<SwipeRefreshLayout>(R.id.swiperefresh)
+ refreshLayout.isRefreshing = false
+ refreshLayout.setOnRefreshListener {
+ Log.v(TAG, "refreshing!")
+ fetchHistory()
+ }
+
+ this.isLoading.observe(this, androidx.lifecycle.Observer { loading ->
+ Log.v(TAG, "setting refreshing to ${loading}")
+ refreshLayout.isRefreshing = loading
+ })
+
return view
}
+
+ companion object {
+ val TAG = "taler-merchant"
+ }
}
diff --git a/app/src/main/java/net/taler/merchantpos/MerchantSettings.kt b/app/src/main/java/net/taler/merchantpos/MerchantSettings.kt
index 1903bce..7797dcb 100644
--- a/app/src/main/java/net/taler/merchantpos/MerchantSettings.kt
+++ b/app/src/main/java/net/taler/merchantpos/MerchantSettings.kt
@@ -1,21 +1,128 @@
package net.taler.merchantpos
+import android.content.Context
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import android.widget.Button
+import android.widget.EditText
+import android.widget.TextView
+import androidx.lifecycle.ViewModelProviders
+import com.android.volley.Request
+import com.android.volley.RequestQueue
+import com.android.volley.Response
+import com.android.volley.VolleyError
+import com.android.volley.toolbox.Volley
+import com.google.android.material.snackbar.Snackbar
+import org.json.JSONObject
/**
* Fragment that displays merchant settings.
*/
class MerchantSettings : Fragment() {
+
+ private lateinit var queue: RequestQueue
+ private lateinit var model: PosTerminalViewModel
+
+ private var newConfig: MerchantConfig? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ model = activity?.run {
+ ViewModelProviders.of(this)[PosTerminalViewModel::class.java]
+ } ?: throw Exception("Invalid Activity")
+
+ queue = Volley.newRequestQueue(context)
+ }
+
+ private fun reset(view: View) {
+ val backendUrlEdit = view.findViewById<EditText>(R.id.edit_settings_backend_url)
+ backendUrlEdit.setText(model.merchantConfig!!.baseUrl, TextView.BufferType.EDITABLE)
+
+ val backendInstanceEdit = view.findViewById<EditText>(R.id.edit_settings_instance)
+ backendInstanceEdit.setText(model.merchantConfig!!.instance, TextView.BufferType.EDITABLE)
+
+ val backendApiKeyEdit = view.findViewById<EditText>(R.id.edit_settings_apikey)
+ backendApiKeyEdit.setText(model.merchantConfig!!.apiKey, TextView.BufferType.EDITABLE)
+
+ val currencyView = view.findViewById<TextView>(R.id.text_settings_currency)
+ currencyView.text = model.merchantConfig!!.currency
+ }
+
+
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
- // Inflate the layout for this fragment
- return inflater.inflate(R.layout.fragment_merchant_settings, container, false)
+ val view = inflater.inflate(R.layout.fragment_merchant_settings, container, false)
+
+ reset(view)
+
+ val buttonApply = view.findViewById<Button>(R.id.button_settings_apply)
+ buttonApply.setOnClickListener {
+
+ val backendUrlEdit = view.findViewById<EditText>(R.id.edit_settings_backend_url)
+ val backendInstanceEdit = view.findViewById<EditText>(R.id.edit_settings_instance)
+ val backendApiKeyEdit = view.findViewById<EditText>(R.id.edit_settings_apikey)
+
+ val config = MerchantConfig(
+ backendUrlEdit.text.toString(),
+ backendInstanceEdit.text.toString(),
+ backendApiKeyEdit.text.toString(),
+ "UNKNOWN"
+ )
+
+ newConfig = config
+
+ val req = MerchantInternalRequest(
+ Request.Method.GET,
+ config,
+ "config",
+ mapOf("instance" to config.instance),
+ null,
+ Response.Listener { onConfigReceived(it) },
+ Response.ErrorListener { onNetworkError(it) })
+
+ queue.add(req)
+
+ }
+
+ val buttonReset = view.findViewById<Button>(R.id.button_settings_reset)
+ buttonReset.setOnClickListener {
+ reset(view)
+ }
+
+ return view
+ }
+
+ private fun onConfigReceived(it: JSONObject) {
+ val currency = it.getString("currency")
+ val mySnackbar =
+ Snackbar.make(view!!, "Changed to new ${currency} merchant", Snackbar.LENGTH_SHORT)
+
+ val config = this.newConfig!!.copy(currency = currency)
+ this.newConfig = null
+ model.merchantConfig = config
+
+ val currencyView = view!!.findViewById<TextView>(R.id.text_settings_currency)
+ currencyView.text = currency
+
+ mySnackbar.show()
+
+ val prefs = activity!!.getSharedPreferences("taler-merchant-terminal", Context.MODE_PRIVATE)
+ prefs.edit().putString("merchantBackendUrl", config.baseUrl)
+ .putString("merchantBackendInstance", config.instance)
+ .putString("merchantBackendApiKey", config.apiKey)
+ .putString("merchantBackendCurrency", config.currency)
+ }
+
+ private fun onNetworkError(it: VolleyError) {
+ val mySnackbar =
+ Snackbar.make(view!!, "Error: Invalid Configuration", Snackbar.LENGTH_SHORT)
+ mySnackbar.show()
}
}
diff --git a/app/src/main/res/layout/fragment_create_payment.xml b/app/src/main/res/layout/fragment_create_payment.xml
index f72f263..c3f2e5f 100644
--- a/app/src/main/res/layout/fragment_create_payment.xml
+++ b/app/src/main/res/layout/fragment_create_payment.xml
@@ -36,7 +36,7 @@
android:text="Amount (TESTKUDOS)"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:id="@+id/textView6"/>
+ android:id="@+id/text_create_payment_amount_label"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/app/src/main/res/layout/fragment_merchant_history.xml b/app/src/main/res/layout/fragment_merchant_history.xml
index 92abdf7..abb757c 100644
--- a/app/src/main/res/layout/fragment_merchant_history.xml
+++ b/app/src/main/res/layout/fragment_merchant_history.xml
@@ -1,32 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
-<androidx.core.widget.NestedScrollView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
+<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/swiperefresh"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_margin="15dp">
+ android:layout_height="match_parent">
- <LinearLayout
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/list_history"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical">
+ android:scrollbars="vertical" />
- <View
- android:id="@+id/header"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
-
- <androidx.recyclerview.widget.RecyclerView
- android:id="@+id/list_history"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:scrollbars="vertical"
- android:layout_marginTop="47dp" android:layout_marginEnd="75dp"
- android:layout_marginBottom="17dp"/>
-
- <Button
- android:text="Button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" android:id="@+id/button2"/>
- </LinearLayout>
-</androidx.core.widget.NestedScrollView>
+</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
diff --git a/app/src/main/res/layout/fragment_merchant_settings.xml b/app/src/main/res/layout/fragment_merchant_settings.xml
index 8fcf233..b6e3707 100644
--- a/app/src/main/res/layout/fragment_merchant_settings.xml
+++ b/app/src/main/res/layout/fragment_merchant_settings.xml
@@ -11,5 +11,98 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Merchant Backend Base URL" />
+
+ <EditText
+ android:id="@+id/edit_settings_backend_url"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ems="10"
+ android:inputType="text"
+ android:text="Name" />
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="40dp" />
+
+ <TextView
+ android:id="@+id/textView4"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Merchant Instance" />
+
+ <EditText
+ android:id="@+id/edit_settings_instance"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ems="10"
+ android:inputType="text"
+ android:text="Name" />
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="40dp" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="API Key" />
+
+ <EditText
+ android:id="@+id/edit_settings_apikey"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ems="10"
+ android:inputType="textPassword" />
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="40dp" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Currency" />
+
+ <TextView
+ android:id="@+id/text_settings_currency"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:textAppearance="@style/TextAppearance.AppCompat.Display1" />
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <Button
+ android:id="@+id/button_settings_reset"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|right"
+ android:text="Reset" />
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+
+ <Button
+ android:id="@+id/button_settings_apply"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|right"
+ android:text="Apply" />
+ </LinearLayout>
</LinearLayout>
+
</FrameLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/history_row.xml b/app/src/main/res/layout/history_row.xml
index a67cf37..12b93d5 100644
--- a/app/src/main/res/layout/history_row.xml
+++ b/app/src/main/res/layout/history_row.xml
@@ -1,7 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/historyText"
- android:textSize="20sp">
-</TextView> \ No newline at end of file
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:orientation="vertical"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_marginHorizontal="15dp"
+ android:layout_marginVertical="5dp">
+
+ <TextView
+ android:id="@+id/text_history_summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="24sp"
+ android:textStyle="bold"
+ tools:text="One Cappuccino" />
+
+ <TextView
+ android:id="@+id/text_history_amount"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="1 Euro"
+ android:textSize="20sp"
+ android:textStyle="bold" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Received at "
+ android:textAllCaps="false"
+ android:textSize="20sp"
+ android:textStyle="italic" />
+
+
+ <TextView
+ android:id="@+id/text_history_time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="2019-08-31 14:25"
+ android:textSize="20sp" />
+
+ </LinearLayout>
+
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Ref. No: "
+ android:textAllCaps="false"
+ android:textSize="20sp"
+ android:textStyle="italic" />
+
+ <TextView
+ android:id="@+id/text_history_order_id"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="2019.242-014B6QPFMHCTY"
+ android:textAllCaps="false"
+ android:textSize="20sp"
+ android:textStyle="italic" />
+ </LinearLayout>
+
+</LinearLayout>