Skip to content

Commit 8ba1078

Browse files
authored
Add scroll to top/bottom in note view for long notes (#866)
1 parent 8a4b959 commit 8ba1078

File tree

11 files changed

+115
-37
lines changed

11 files changed

+115
-37
lines changed

TRANSLATIONS.md

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,34 +19,34 @@ See [Android Translations Converter](https://github.com/Crustack/android-transla
1919
<!-- translations:start -->
2020
| Language | Coverage |
2121
|----------|----------|
22-
| 🇺🇸 English | 100% (331/331) |
23-
| 🇪🇸 Catalan | 19% (65/331) |
24-
| 🇨🇿 Czech | 94% (313/331) |
25-
| 🇩🇰 Danish | 20% (69/331) |
26-
| 🇩🇪 German | 98% (327/331) |
27-
| 🇬🇷 Greek | 21% (72/331) |
28-
| 🇪🇸 Spanish | 94% (314/331) |
29-
| 🇫🇷 French | 98% (327/331) |
30-
| 🇭🇺 Hungarian | 19% (65/331) |
31-
| 🇮🇩 Indonesian | 22% (75/331) |
32-
| 🇮🇹 Italian | 87% (291/331) |
33-
| 🇯🇵 Japanese | 22% (73/331) |
34-
| 🇲🇲 Burmese | 27% (90/331) |
35-
| 🇳🇴 Norwegian Bokmål | 32% (106/331) |
36-
| 🇳🇱 Dutch | 64% (212/331) |
37-
| 🇳🇴 Norwegian Nynorsk | 32% (106/331) |
38-
| 🇵🇱 Polish | 90% (300/331) |
39-
| 🇧🇷 Portuguese (Brazil) | 94% (312/331) |
40-
| 🇵🇹 Portuguese (Portugal) | 21% (71/331) |
41-
| 🇷🇴 Romanian | 90% (301/331) |
42-
| 🇷🇺 Russian | 92% (305/331) |
43-
| 🇸🇰 Slovak | 19% (65/331) |
44-
| 🇸🇮 Slovenian | 32% (109/331) |
45-
| 🇸🇪 Swedish | 19% (63/331) |
46-
| 🇵🇭 Tagalog | 19% (65/331) |
47-
| 🇹🇷 Turkish | 22% (73/331) |
48-
| 🇺🇦 Ukrainian | 98% (326/331) |
49-
| 🇻🇳 Vietnamese | 32% (107/331) |
50-
| 🇨🇳 Chinese (Simplified) | 97% (323/331) |
51-
| 🇹🇼 Chinese (Traditional) | 88% (294/331) |
22+
| 🇺🇸 English | 100% (333/333) |
23+
| 🇪🇸 Catalan | 19% (65/333) |
24+
| 🇨🇿 Czech | 93% (313/333) |
25+
| 🇩🇰 Danish | 20% (69/333) |
26+
| 🇩🇪 German | 98% (327/333) |
27+
| 🇬🇷 Greek | 21% (72/333) |
28+
| 🇪🇸 Spanish | 94% (314/333) |
29+
| 🇫🇷 French | 98% (327/333) |
30+
| 🇭🇺 Hungarian | 19% (65/333) |
31+
| 🇮🇩 Indonesian | 22% (75/333) |
32+
| 🇮🇹 Italian | 87% (291/333) |
33+
| 🇯🇵 Japanese | 21% (73/333) |
34+
| 🇲🇲 Burmese | 27% (90/333) |
35+
| 🇳🇴 Norwegian Bokmål | 31% (106/333) |
36+
| 🇳🇱 Dutch | 63% (212/333) |
37+
| 🇳🇴 Norwegian Nynorsk | 31% (106/333) |
38+
| 🇵🇱 Polish | 90% (300/333) |
39+
| 🇧🇷 Portuguese (Brazil) | 93% (312/333) |
40+
| 🇵🇹 Portuguese (Portugal) | 21% (71/333) |
41+
| 🇷🇴 Romanian | 90% (301/333) |
42+
| 🇷🇺 Russian | 91% (305/333) |
43+
| 🇸🇰 Slovak | 19% (65/333) |
44+
| 🇸🇮 Slovenian | 32% (109/333) |
45+
| 🇸🇪 Swedish | 18% (63/333) |
46+
| 🇵🇭 Tagalog | 19% (65/333) |
47+
| 🇹🇷 Turkish | 21% (73/333) |
48+
| 🇺🇦 Ukrainian | 97% (326/333) |
49+
| 🇻🇳 Vietnamese | 32% (107/333) |
50+
| 🇨🇳 Chinese (Simplified) | 96% (323/333) |
51+
| 🇹🇼 Chinese (Traditional) | 88% (294/333) |
5252
<!-- translations:end -->

app/src/main/java/com/philkes/notallyx/presentation/activity/note/EditActivity.kt

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ import com.philkes.notallyx.utils.findWebUrls
9898
import com.philkes.notallyx.utils.getFileName
9999
import com.philkes.notallyx.utils.getMimeType
100100
import com.philkes.notallyx.utils.getUriForFile
101+
import com.philkes.notallyx.utils.isInLandscapeMode
101102
import com.philkes.notallyx.utils.log
102103
import com.philkes.notallyx.utils.mergeSkipFirst
103104
import com.philkes.notallyx.utils.observeSkipFirst
@@ -132,6 +133,8 @@ abstract class EditActivity(private val type: Type) :
132133
internal lateinit var changeHistory: ChangeHistory
133134
protected var undo: View? = null
134135
protected var redo: View? = null
136+
protected var jumpToTop: View? = null
137+
protected var jumpToBottom: View? = null
135138

136139
protected var colorInt: Int = -1
137140
protected var inputMethodManager: InputMethodManager? = null
@@ -546,6 +549,22 @@ abstract class EditActivity(private val type: Type) :
546549

547550
protected fun isInSearchMode(): Boolean = binding.EnterSearchKeyword.visibility == VISIBLE
548551

552+
protected fun updateJumpButtonsVisibility(manualSize: Int? = null) {
553+
jumpToTop?.post {
554+
val show =
555+
when (notallyModel.type) {
556+
Type.NOTE ->
557+
(manualSize ?: binding.EnterBody.lineCount) >
558+
(if (isInLandscapeMode) 30 else 75)
559+
Type.LIST ->
560+
(manualSize ?: notallyModel.items.size) >
561+
(if (isInLandscapeMode) 15 else 25)
562+
}
563+
jumpToTop?.isVisible = show
564+
jumpToBottom?.isVisible = show
565+
}
566+
}
567+
549568
protected fun endSearch() {
550569
binding.EnterSearchKeyword.apply {
551570
visibility = GONE
@@ -570,6 +589,14 @@ abstract class EditActivity(private val type: Type) :
570589
}
571590
binding.BottomAppBarCenter.apply {
572591
removeAllViews()
592+
jumpToTop =
593+
addIconButton(
594+
R.string.jump_to_top,
595+
R.drawable.vertical_align_top,
596+
marginStart = 0,
597+
) {
598+
binding.ScrollView.apply { post { fullScroll(View.FOCUS_UP) } }
599+
}
573600
undo =
574601
addIconButton(
575602
R.string.undo,
@@ -613,6 +640,26 @@ abstract class EditActivity(private val type: Type) :
613640
}
614641
}
615642
.apply { isEnabled = changeHistory.canRedo.value }
643+
jumpToBottom =
644+
addIconButton(
645+
R.string.jump_to_bottom,
646+
R.drawable.vertical_align_bottom,
647+
marginStart = 2,
648+
) {
649+
binding.ScrollView.apply {
650+
post {
651+
val lastChild: View? = binding.ScrollView.getChildAt(0)
652+
if (lastChild != null) {
653+
val bottom: Int =
654+
lastChild.bottom + binding.ScrollView.paddingBottom
655+
binding.ScrollView.smoothScrollTo(0, bottom)
656+
} else {
657+
fullScroll(View.FOCUS_DOWN)
658+
}
659+
}
660+
}
661+
}
662+
updateJumpButtonsVisibility()
616663
}
617664
binding.BottomAppBarRight.apply {
618665
removeAllViews()

app/src/main/java/com/philkes/notallyx/presentation/activity/note/EditListActivity.kt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -241,11 +241,13 @@ class EditListActivity : EditActivity(Type.LIST), MoreListActions {
241241
endSearch()
242242
}
243243
},
244-
) { _ ->
245-
if (isInSearchMode() && search.results.value > 0) {
246-
updateSearchResults(search.query)
247-
}
248-
}
244+
{ _ ->
245+
if (isInSearchMode() && search.results.value > 0) {
246+
updateSearchResults(search.query)
247+
}
248+
},
249+
{ items -> updateJumpButtonsVisibility(items) },
250+
)
249251
adapter =
250252
ListItemAdapter(
251253
colorInt,

app/src/main/java/com/philkes/notallyx/presentation/activity/note/EditNoteActivity.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ class EditNoteActivity : EditActivity(Type.NOTE), AddNoteActions {
162162
notallyModel.body = text
163163
if (textChanged) {
164164
updateSearchResults(search.query)
165+
updateJumpButtonsVisibility()
165166
}
166167
}
167168
}

app/src/main/java/com/philkes/notallyx/presentation/view/note/listitem/ListManager.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package com.philkes.notallyx.presentation.view.note.listitem
33
import android.util.Log
44
import android.view.View
55
import android.view.inputmethod.InputMethodManager
6-
import android.widget.EditText
76
import androidx.recyclerview.widget.RecyclerView
87
import com.philkes.notallyx.data.model.ListItem
98
import com.philkes.notallyx.data.model.check
@@ -48,6 +47,7 @@ class ListManager(
4847
private val inputMethodManager: InputMethodManager?,
4948
private val endSearch: (() -> Unit)?,
5049
val refreshSearch: ((refocusView: View?) -> Unit)?,
50+
val onItemSizeChanged: ((items: Int) -> Unit)?,
5151
) {
5252
lateinit var adapter: ListItemAdapter
5353
var checkedAdapter: CheckedListItemAdapter? = null
@@ -151,6 +151,7 @@ class ListManager(
151151
inputMethodManager?.let { viewHolder.focusEditText(inputMethodManager = it) }
152152
}
153153
}
154+
onItemSizeChanged?.invoke(items.size + (itemsChecked?.size() ?: 0))
154155
}
155156

156157
/**
@@ -201,6 +202,7 @@ class ListManager(
201202
if (pushChange && result) {
202203
changeHistory.push(ListDeleteChange(stateBefore, getState(), this))
203204
}
205+
onItemSizeChanged?.invoke(items.size + (itemsChecked?.size() ?: 0))
204206
return result
205207
}
206208

@@ -372,6 +374,7 @@ class ListManager(
372374
if (pushChange) {
373375
changeHistory.push(DeleteCheckedChange(stateBefore, getState(), this))
374376
}
377+
onItemSizeChanged?.invoke(items.size + (itemsChecked?.size() ?: 0))
375378
}
376379

377380
fun findParent(item: ListItem) = items.findParent(item) ?: itemsChecked?.findParent(item)

app/src/main/java/com/philkes/notallyx/utils/AndroidExtensions.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,9 @@ fun Activity.showErrorDialog(
246246
.show()
247247
}
248248

249+
val Activity.isInLandscapeMode
250+
get() = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
251+
249252
private const val MAX_LOGS_FILE_SIZE_KB: Long = 2048
250253

251254
private fun Context.logToFile(
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="960"
5+
android:viewportHeight="960"
6+
android:tint="?attr/colorControlNormal">
7+
<path
8+
android:fillColor="@android:color/white"
9+
android:pathData="M160,840L160,760L800,760L800,840L160,840ZM480,680L280,480L336,424L440,528L440,120L520,120L520,528L624,424L680,480L480,680Z"/>
10+
</vector>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="960"
5+
android:viewportHeight="960"
6+
android:tint="?attr/colorControlNormal">
7+
<path
8+
android:fillColor="@android:color/white"
9+
android:pathData="M160,200L160,120L800,120L800,200L160,200ZM440,840L440,432L336,536L280,480L480,280L680,480L624,536L520,432L520,840L440,840Z"/>
10+
</vector>

app/src/main/res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,8 @@
216216
<string name="item">Item</string>
217217
<string name="json_files">JSON Files</string>
218218
<string name="json_files_help">In order to import your Notes from JSON files (single file or folder), click Import. Every valid JSON file is imported as a separate note, the file’s name becomes the note’s title.</string>
219+
<string name="jump_to_bottom">Jump to bottom</string>
220+
<string name="jump_to_top">Jump to top</string>
219221
<string name="label_exists">Label exists</string>
220222
<string name="label_visibility">Hide/Show the label in the navigation panel</string>
221223
<string name="labels">Labels</string>

app/src/test/kotlin/com/philkes/notallyx/recyclerview/listmanager/ListManagerTestBase.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ open class ListManagerTestBase {
5959
listItemVH = mock(ListItemVH::class.java)
6060
preferences = mock(NotallyXPreferences::class.java)
6161
listManager =
62-
ListManager(recyclerView, changeHistory, preferences, inputMethodManager, {}) {}
62+
ListManager(recyclerView, changeHistory, preferences, inputMethodManager, {}, {}, null)
6363
// Prepare view holder
6464
`when`(recyclerView.findViewHolderForAdapterPosition(anyInt())).thenReturn(listItemVH)
6565
}

0 commit comments

Comments
 (0)