gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-taler-android] 03/03: [wallet] show ToS markdown in expandable se


From: gnunet
Subject: [taler-taler-android] 03/03: [wallet] show ToS markdown in expandable sections
Date: Thu, 30 Apr 2020 19:33:42 +0200

This is an automated email from the git hooks/post-receive script.

torsten-grote pushed a commit to branch master
in repository taler-android.

commit 056be53a8d51fb6e45167f5d1ec317513b87a906
Author: Torsten Grote <address@hidden>
AuthorDate: Thu Apr 30 14:33:08 2020 -0300

    [wallet] show ToS markdown in expandable sections
---
 build.gradle                                       |  2 +-
 wallet/build.gradle                                |  8 +-
 .../wallet/withdraw/ReviewExchangeTosFragment.kt   | 29 ++++++-
 .../java/net/taler/wallet/withdraw/TosAdapter.kt   | 90 ++++++++++++++++++++++
 .../java/net/taler/wallet/withdraw/TosSection.kt   | 65 ++++++++++++++++
 .../main/res/drawable/ic_keyboard_arrow_down.xml   |  9 +++
 .../src/main/res/drawable/ic_keyboard_arrow_up.xml |  9 +++
 .../res/layout/fragment_review_exchange_tos.xml    | 37 +++++----
 wallet/src/main/res/layout/list_item_tos.xml       | 69 +++++++++++++++++
 wallet/src/main/res/values/strings.xml             |  1 +
 10 files changed, 298 insertions(+), 21 deletions(-)

diff --git a/build.gradle b/build.gradle
index 3955891..ec72fa3 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,6 +1,6 @@
 buildscript {
     ext.kotlin_version = '1.3.72'
-    ext.nav_version = "2.2.1"
+    ext.nav_version = "2.2.2"
     ext.build_tools_version = "29.0.2"
     repositories {
         google()
diff --git a/wallet/build.gradle b/wallet/build.gradle
index a872e8c..28431b3 100644
--- a/wallet/build.gradle
+++ b/wallet/build.gradle
@@ -67,7 +67,7 @@ dependencies {
     implementation project(":taler-kotlin-common")
     implementation 'net.taler:akono:0.1'
 
-    implementation 'androidx.preference:preference:1.1.0'
+    implementation 'androidx.preference:preference:1.1.1'
     implementation 'com.google.android.material:material:1.1.0'
     implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
 
@@ -89,6 +89,12 @@ dependencies {
     // Nicer ProgressBar
     implementation 'me.zhanghai.android.materialprogressbar:library:1.6.1'
 
+    // Markdown rendering
+    final def  markwon_version =  '4.3.1'
+    implementation  "io.noties.markwon:core:$markwon_version"
+    implementation  "io.noties.markwon:ext-tables:$markwon_version"
+    implementation  "io.noties.markwon:recycler:$markwon_version"
+
     // JSON parsing and serialization
     implementation 'com.fasterxml.jackson.module:jackson-module-kotlin:2.10.2'
 
diff --git 
a/wallet/src/main/java/net/taler/wallet/withdraw/ReviewExchangeTosFragment.kt 
b/wallet/src/main/java/net/taler/wallet/withdraw/ReviewExchangeTosFragment.kt
index 47b6f14..ffaef5a 100644
--- 
a/wallet/src/main/java/net/taler/wallet/withdraw/ReviewExchangeTosFragment.kt
+++ 
b/wallet/src/main/java/net/taler/wallet/withdraw/ReviewExchangeTosFragment.kt
@@ -16,7 +16,6 @@
 
 package net.taler.wallet.withdraw
 
-
 import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
@@ -25,16 +24,20 @@ import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
 import androidx.lifecycle.Observer
 import androidx.navigation.fragment.findNavController
+import io.noties.markwon.Markwon
 import kotlinx.android.synthetic.main.fragment_review_exchange_tos.*
 import net.taler.common.fadeIn
 import net.taler.common.fadeOut
-import net.taler.wallet.R
 import net.taler.wallet.MainViewModel
+import net.taler.wallet.R
+import java.text.ParseException
 
 class ReviewExchangeTosFragment : Fragment() {
 
     private val model: MainViewModel by activityViewModels()
     private val withdrawManager by lazy { model.withdrawManager }
+    private val markwon by lazy { Markwon.builder(requireContext()).build() }
+    private val adapter by lazy { TosAdapter(markwon) }
 
     override fun onCreateView(
         inflater: LayoutInflater,
@@ -53,8 +56,18 @@ class ReviewExchangeTosFragment : Fragment() {
         withdrawManager.withdrawStatus.observe(viewLifecycleOwner, Observer {
             when (it) {
                 is WithdrawStatus.TermsOfServiceReviewRequired -> {
-                    tosTextView.text = it.tosText
-                    tosTextView.fadeIn()
+                    val sections = try {
+                        // TODO remove next line once exchange delivers proper 
markdown
+                        val text = it.tosText.replace("****************", 
"================")
+                        parseTos(markwon, text)
+                    } catch (e: ParseException) {
+                        onTosError(e.message ?: "Unknown Error")
+                        return@Observer
+                    }
+                    adapter.setSections(sections)
+                    tosList.adapter = adapter
+                    tosList.fadeIn()
+
                     acceptTosCheckBox.fadeIn()
                     progressBar.fadeOut()
                 }
@@ -68,4 +81,12 @@ class ReviewExchangeTosFragment : Fragment() {
         })
     }
 
+    private fun onTosError(msg: String) {
+        tosList.fadeIn()
+        progressBar.fadeOut()
+        buttonCard.fadeOut()
+        errorView.text = getString(R.string.exchange_tos_error, "\n\n$msg")
+        errorView.fadeIn()
+    }
+
 }
diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/TosAdapter.kt 
b/wallet/src/main/java/net/taler/wallet/withdraw/TosAdapter.kt
new file mode 100644
index 0000000..74a798f
--- /dev/null
+++ b/wallet/src/main/java/net/taler/wallet/withdraw/TosAdapter.kt
@@ -0,0 +1,90 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2020 Taler Systems S.A.
+ *
+ * GNU Taler is free software; you can redistribute it and/or modify it under 
the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 3, or (at your option) any later version.
+ *
+ * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+ * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+package net.taler.wallet.withdraw
+
+import android.transition.TransitionManager.beginDelayedTransition
+import android.view.LayoutInflater
+import android.view.View
+import android.view.View.GONE
+import android.view.View.VISIBLE
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+import io.noties.markwon.Markwon
+import net.taler.wallet.R
+
+class TosAdapter(
+    private val markwon: Markwon
+) : RecyclerView.Adapter<TosAdapter.TosSectionViewHolder>() {
+
+    private val items = ArrayList<TosSection>()
+
+    init {
+        setHasStableIds(true)
+    }
+
+    override fun getItemCount() = items.size
+
+    override fun getItemId(position: Int): Long {
+        return items[position].node.hashCode().toLong()
+    }
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): 
TosSectionViewHolder {
+        val v = 
LayoutInflater.from(parent.context).inflate(R.layout.list_item_tos, parent, 
false)
+        return TosSectionViewHolder(v)
+    }
+
+    override fun onBindViewHolder(holder: TosSectionViewHolder, position: Int) 
{
+        holder.bind(items[position])
+    }
+
+    fun setSections(sections: List<TosSection>) {
+        items.clear()
+        items.addAll(sections)
+        notifyDataSetChanged()
+    }
+
+    inner class TosSectionViewHolder(private val v: View) : 
RecyclerView.ViewHolder(v) {
+        private val sectionTitle: TextView = v.findViewById(R.id.sectionTitle)
+        private val expandButton: ImageView = v.findViewById(R.id.expandButton)
+        private val sectionText: TextView = v.findViewById(R.id.sectionText)
+
+        fun bind(item: TosSection) {
+            sectionTitle.text = item.title
+            showSection(item, item.expanded)
+            val onClickListener = View.OnClickListener {
+                if (!item.expanded) beginDelayedTransition(v as ViewGroup)
+                item.expanded = !item.expanded
+                showSection(item, item.expanded)
+            }
+            sectionTitle.setOnClickListener(onClickListener)
+        }
+
+        private fun showSection(item: TosSection, show: Boolean) {
+            if (show) {
+                expandButton.setImageResource(R.drawable.ic_keyboard_arrow_up)
+                markwon.setParsedMarkdown(sectionText, 
markwon.render(item.node))
+                sectionText.visibility = VISIBLE
+            } else {
+                
expandButton.setImageResource(R.drawable.ic_keyboard_arrow_down)
+                sectionText.visibility = GONE
+            }
+        }
+    }
+
+}
diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/TosSection.kt 
b/wallet/src/main/java/net/taler/wallet/withdraw/TosSection.kt
new file mode 100644
index 0000000..72a9e34
--- /dev/null
+++ b/wallet/src/main/java/net/taler/wallet/withdraw/TosSection.kt
@@ -0,0 +1,65 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2020 Taler Systems S.A.
+ *
+ * GNU Taler is free software; you can redistribute it and/or modify it under 
the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 3, or (at your option) any later version.
+ *
+ * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+ * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+package net.taler.wallet.withdraw
+
+import io.noties.markwon.Markwon
+import org.commonmark.node.Document
+import org.commonmark.node.Heading
+import org.commonmark.node.Node
+import org.commonmark.node.Text
+import java.text.ParseException
+
+data class TosSection(
+    val title: String,
+    val node: Node,
+    var expanded: Boolean = false
+)
+
+@Throws(ParseException::class)
+internal fun parseTos(markwon: Markwon, text: String): List<TosSection> {
+    var node: Node? =
+        markwon.parse(text).firstChild ?: throw ParseException("Invalid 
markdown", 0)
+    var lastHeading: String? = null
+    var section = Document()
+    val sections = ArrayList<TosSection>()
+    while (node != null) {
+        val next: Node? = node.next
+        if (node is Heading && node.level == 1) {
+            // if lastHeading exists, close previous section
+            if (lastHeading != null) {
+                sections.add(TosSection(lastHeading, section))
+                section = Document()
+            }
+            // check that this is a plain heading
+            if (node.firstChild !is Text || node.firstChild.next != null) {
+                throw ParseException(
+                    "Primary heading includes more than just text", 
sections.size
+                )
+            }
+            // start new section
+            lastHeading = (node.firstChild as Text).literal
+        } else if (lastHeading == null) {
+            throw ParseException("Found text before first primary heading", 0)
+        } else {
+            section.appendChild(node)
+        }
+        node = next
+    }
+    check(lastHeading != null)
+    sections.add(TosSection(lastHeading, section))
+    return sections
+}
diff --git a/wallet/src/main/res/drawable/ic_keyboard_arrow_down.xml 
b/wallet/src/main/res/drawable/ic_keyboard_arrow_down.xml
new file mode 100644
index 0000000..c7ba402
--- /dev/null
+++ b/wallet/src/main/res/drawable/ic_keyboard_arrow_down.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android";
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M7.41,7.84L12,12.42l4.59,-4.58L18,9.25l-6,6 -6,-6z" 
/>
+</vector>
diff --git a/wallet/src/main/res/drawable/ic_keyboard_arrow_up.xml 
b/wallet/src/main/res/drawable/ic_keyboard_arrow_up.xml
new file mode 100644
index 0000000..328e17c
--- /dev/null
+++ b/wallet/src/main/res/drawable/ic_keyboard_arrow_up.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android";
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M7.41,15.41L12,10.83l4.59,4.58L18,14l-6,-6 -6,6z" />
+</vector>
diff --git a/wallet/src/main/res/layout/fragment_review_exchange_tos.xml 
b/wallet/src/main/res/layout/fragment_review_exchange_tos.xml
index 2587c1a..ec8d996 100644
--- a/wallet/src/main/res/layout/fragment_review_exchange_tos.xml
+++ b/wallet/src/main/res/layout/fragment_review_exchange_tos.xml
@@ -21,36 +21,43 @@
     android:layout_height="match_parent"
     tools:context=".withdraw.ReviewExchangeTosFragment">
 
-    <ScrollView
-        android:id="@+id/tosScrollView"
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/tosList"
         android:layout_width="0dp"
         android:layout_height="0dp"
+        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
         app:layout_constraintBottom_toTopOf="@+id/buttonCard"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent">
-
-        <TextView
-            android:id="@+id/tosTextView"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:padding="16dp"
-            android:visibility="invisible"
-            tools:text="@tools:sample/lorem/random"
-            tools:visibility="visible" />
-
-    </ScrollView>
+        app:layout_constraintTop_toTopOf="parent"
+        tools:listitem="@layout/list_item_tos" />
 
     <ProgressBar
         android:id="@+id/progressBar"
         style="?android:attr/progressBarStyleLarge"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        app:layout_constraintBottom_toBottomOf="@+id/tosScrollView"
+        app:layout_constraintBottom_toBottomOf="@+id/tosList"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
 
+    <TextView
+        android:id="@+id/errorView"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_margin="16dp"
+        android:gravity="center"
+        android:textColor="@color/red"
+        android:textSize="16sp"
+        android:visibility="invisible"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        tools:text="@string/exchange_tos_error"
+        tools:visibility="visible" />
+
     <com.google.android.material.card.MaterialCardView
         android:id="@+id/buttonCard"
         style="@style/BottomCard"
diff --git a/wallet/src/main/res/layout/list_item_tos.xml 
b/wallet/src/main/res/layout/list_item_tos.xml
new file mode 100644
index 0000000..7a584dc
--- /dev/null
+++ b/wallet/src/main/res/layout/list_item_tos.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ This file is part of GNU Taler
+  ~ (C) 2020 Taler Systems S.A.
+  ~
+  ~ GNU Taler is free software; you can redistribute it and/or modify it under 
the
+  ~ terms of the GNU General Public License as published by the Free Software
+  ~ Foundation; either version 3, or (at your option) any later version.
+  ~
+  ~ GNU Taler is distributed in the hope that it will be useful, but WITHOUT 
ANY
+  ~ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+  ~ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+  ~
+  ~ You should have received a copy of the GNU General Public License along 
with
+  ~ GNU Taler; see the file COPYING.  If not, see 
<http://www.gnu.org/licenses/>
+  -->
+
+<androidx.cardview.widget.CardView 
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="wrap_content"
+    app:cardUseCompatPadding="true">
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+        <TextView
+            android:id="@+id/sectionTitle"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:background="?attr/selectableItemBackground"
+            android:paddingStart="8dp"
+            android:paddingTop="8dp"
+            android:paddingEnd="56dp"
+            android:paddingBottom="8dp"
+            android:textAppearance="@style/TextAppearance.AppCompat.Headline"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            tools:text="A Terms of Service section title that might be rather 
long in some cases" />
+
+        <ImageView
+            android:id="@+id/expandButton"
+            android:layout_width="48dp"
+            android:layout_height="0dp"
+            android:padding="8dp"
+            android:scaleType="center"
+            android:src="@drawable/ic_keyboard_arrow_up"
+            app:layout_constraintBottom_toBottomOf="@+id/sectionTitle"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintTop_toTopOf="@+id/sectionTitle"
+            app:tint="?android:attr/textColorPrimary"
+            tools:ignore="ContentDescription" />
+
+        <TextView
+            android:id="@+id/sectionText"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:padding="8dp"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/sectionTitle"
+            tools:text="@tools:sample/lorem/random" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+</androidx.cardview.widget.CardView>
diff --git a/wallet/src/main/res/values/strings.xml 
b/wallet/src/main/res/values/strings.xml
index cc846cd..dd3a810 100644
--- a/wallet/src/main/res/values/strings.xml
+++ b/wallet/src/main/res/values/strings.xml
@@ -128,6 +128,7 @@ GNU Taler is immune against many types of fraud, such as 
phishing of credit card
     <string name="exchange_fee_wire_fee_wire_fee">Wire Fee: %s</string>
     <string name="exchange_fee_wire_fee_closing_fee">Closing Fee: %s</string>
     <string name="exchange_tos_accept">Accept Terms of Service</string>
+    <string name="exchange_tos_error">Error showing Terms of Service: 
%s</string>
 
     <string name="pending_operations_title">Pending Operations</string>
     <string name="pending_operations_refuse">Refuse Proposal</string>

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]