diff --git a/TRANSLATIONS.md b/TRANSLATIONS.md index 42b127df..c8dce02f 100644 --- a/TRANSLATIONS.md +++ b/TRANSLATIONS.md @@ -19,34 +19,34 @@ See [Android Translations Converter](https://github.com/Crustack/android-transla | Language | Coverage | |----------|----------| -| ๐Ÿ‡บ๐Ÿ‡ธ English | 100% (331/331) | -| ๐Ÿ‡ช๐Ÿ‡ธ Catalan | 19% (65/331) | -| ๐Ÿ‡จ๐Ÿ‡ฟ Czech | 94% (313/331) | -| ๐Ÿ‡ฉ๐Ÿ‡ฐ Danish | 20% (69/331) | -| ๐Ÿ‡ฉ๐Ÿ‡ช German | 98% (327/331) | -| ๐Ÿ‡ฌ๐Ÿ‡ท Greek | 21% (72/331) | -| ๐Ÿ‡ช๐Ÿ‡ธ Spanish | 94% (314/331) | -| ๐Ÿ‡ซ๐Ÿ‡ท French | 98% (327/331) | -| ๐Ÿ‡ญ๐Ÿ‡บ Hungarian | 19% (65/331) | -| ๐Ÿ‡ฎ๐Ÿ‡ฉ Indonesian | 22% (75/331) | -| ๐Ÿ‡ฎ๐Ÿ‡น Italian | 87% (291/331) | -| ๐Ÿ‡ฏ๐Ÿ‡ต Japanese | 22% (73/331) | -| ๐Ÿ‡ฒ๐Ÿ‡ฒ Burmese | 27% (90/331) | -| ๐Ÿ‡ณ๐Ÿ‡ด Norwegian Bokmรฅl | 32% (106/331) | -| ๐Ÿ‡ณ๐Ÿ‡ฑ Dutch | 64% (212/331) | -| ๐Ÿ‡ณ๐Ÿ‡ด Norwegian Nynorsk | 32% (106/331) | -| ๐Ÿ‡ต๐Ÿ‡ฑ Polish | 90% (300/331) | -| ๐Ÿ‡ง๐Ÿ‡ท Portuguese (Brazil) | 94% (312/331) | -| ๐Ÿ‡ต๐Ÿ‡น Portuguese (Portugal) | 21% (71/331) | -| ๐Ÿ‡ท๐Ÿ‡ด Romanian | 90% (301/331) | -| ๐Ÿ‡ท๐Ÿ‡บ Russian | 92% (305/331) | -| ๐Ÿ‡ธ๐Ÿ‡ฐ Slovak | 19% (65/331) | -| ๐Ÿ‡ธ๐Ÿ‡ฎ Slovenian | 32% (109/331) | -| ๐Ÿ‡ธ๐Ÿ‡ช Swedish | 19% (63/331) | -| ๐Ÿ‡ต๐Ÿ‡ญ Tagalog | 19% (65/331) | -| ๐Ÿ‡น๐Ÿ‡ท Turkish | 22% (73/331) | -| ๐Ÿ‡บ๐Ÿ‡ฆ Ukrainian | 98% (326/331) | -| ๐Ÿ‡ป๐Ÿ‡ณ Vietnamese | 32% (107/331) | -| ๐Ÿ‡จ๐Ÿ‡ณ Chinese (Simplified) | 97% (323/331) | -| ๐Ÿ‡น๐Ÿ‡ผ Chinese (Traditional) | 88% (294/331) | +| ๐Ÿ‡บ๐Ÿ‡ธ English | 100% (333/333) | +| ๐Ÿ‡ช๐Ÿ‡ธ Catalan | 19% (65/333) | +| ๐Ÿ‡จ๐Ÿ‡ฟ Czech | 93% (313/333) | +| ๐Ÿ‡ฉ๐Ÿ‡ฐ Danish | 20% (69/333) | +| ๐Ÿ‡ฉ๐Ÿ‡ช German | 98% (327/333) | +| ๐Ÿ‡ฌ๐Ÿ‡ท Greek | 21% (72/333) | +| ๐Ÿ‡ช๐Ÿ‡ธ Spanish | 94% (314/333) | +| ๐Ÿ‡ซ๐Ÿ‡ท French | 98% (327/333) | +| ๐Ÿ‡ญ๐Ÿ‡บ Hungarian | 19% (65/333) | +| ๐Ÿ‡ฎ๐Ÿ‡ฉ Indonesian | 22% (75/333) | +| ๐Ÿ‡ฎ๐Ÿ‡น Italian | 87% (291/333) | +| ๐Ÿ‡ฏ๐Ÿ‡ต Japanese | 21% (73/333) | +| ๐Ÿ‡ฒ๐Ÿ‡ฒ Burmese | 27% (90/333) | +| ๐Ÿ‡ณ๐Ÿ‡ด Norwegian Bokmรฅl | 31% (106/333) | +| ๐Ÿ‡ณ๐Ÿ‡ฑ Dutch | 63% (212/333) | +| ๐Ÿ‡ณ๐Ÿ‡ด Norwegian Nynorsk | 31% (106/333) | +| ๐Ÿ‡ต๐Ÿ‡ฑ Polish | 90% (300/333) | +| ๐Ÿ‡ง๐Ÿ‡ท Portuguese (Brazil) | 93% (312/333) | +| ๐Ÿ‡ต๐Ÿ‡น Portuguese (Portugal) | 21% (71/333) | +| ๐Ÿ‡ท๐Ÿ‡ด Romanian | 90% (301/333) | +| ๐Ÿ‡ท๐Ÿ‡บ Russian | 91% (305/333) | +| ๐Ÿ‡ธ๐Ÿ‡ฐ Slovak | 19% (65/333) | +| ๐Ÿ‡ธ๐Ÿ‡ฎ Slovenian | 32% (109/333) | +| ๐Ÿ‡ธ๐Ÿ‡ช Swedish | 18% (63/333) | +| ๐Ÿ‡ต๐Ÿ‡ญ Tagalog | 19% (65/333) | +| ๐Ÿ‡น๐Ÿ‡ท Turkish | 21% (73/333) | +| ๐Ÿ‡บ๐Ÿ‡ฆ Ukrainian | 97% (326/333) | +| ๐Ÿ‡ป๐Ÿ‡ณ Vietnamese | 32% (107/333) | +| ๐Ÿ‡จ๐Ÿ‡ณ Chinese (Simplified) | 96% (323/333) | +| ๐Ÿ‡น๐Ÿ‡ผ Chinese (Traditional) | 88% (294/333) | \ No newline at end of file diff --git a/app/src/main/java/com/philkes/notallyx/presentation/activity/note/EditActivity.kt b/app/src/main/java/com/philkes/notallyx/presentation/activity/note/EditActivity.kt index b02a233c..bc670fd0 100644 --- a/app/src/main/java/com/philkes/notallyx/presentation/activity/note/EditActivity.kt +++ b/app/src/main/java/com/philkes/notallyx/presentation/activity/note/EditActivity.kt @@ -98,6 +98,7 @@ import com.philkes.notallyx.utils.findWebUrls import com.philkes.notallyx.utils.getFileName import com.philkes.notallyx.utils.getMimeType import com.philkes.notallyx.utils.getUriForFile +import com.philkes.notallyx.utils.isInLandscapeMode import com.philkes.notallyx.utils.log import com.philkes.notallyx.utils.mergeSkipFirst import com.philkes.notallyx.utils.observeSkipFirst @@ -132,6 +133,8 @@ abstract class EditActivity(private val type: Type) : internal lateinit var changeHistory: ChangeHistory protected var undo: View? = null protected var redo: View? = null + protected var jumpToTop: View? = null + protected var jumpToBottom: View? = null protected var colorInt: Int = -1 protected var inputMethodManager: InputMethodManager? = null @@ -546,6 +549,22 @@ abstract class EditActivity(private val type: Type) : protected fun isInSearchMode(): Boolean = binding.EnterSearchKeyword.visibility == VISIBLE + protected fun updateJumpButtonsVisibility(manualSize: Int? = null) { + jumpToTop?.post { + val show = + when (notallyModel.type) { + Type.NOTE -> + (manualSize ?: binding.EnterBody.lineCount) > + (if (isInLandscapeMode) 30 else 75) + Type.LIST -> + (manualSize ?: notallyModel.items.size) > + (if (isInLandscapeMode) 15 else 25) + } + jumpToTop?.isVisible = show + jumpToBottom?.isVisible = show + } + } + protected fun endSearch() { binding.EnterSearchKeyword.apply { visibility = GONE @@ -570,6 +589,14 @@ abstract class EditActivity(private val type: Type) : } binding.BottomAppBarCenter.apply { removeAllViews() + jumpToTop = + addIconButton( + R.string.jump_to_top, + R.drawable.vertical_align_top, + marginStart = 0, + ) { + binding.ScrollView.apply { post { fullScroll(View.FOCUS_UP) } } + } undo = addIconButton( R.string.undo, @@ -613,6 +640,26 @@ abstract class EditActivity(private val type: Type) : } } .apply { isEnabled = changeHistory.canRedo.value } + jumpToBottom = + addIconButton( + R.string.jump_to_bottom, + R.drawable.vertical_align_bottom, + marginStart = 2, + ) { + binding.ScrollView.apply { + post { + val lastChild: View? = binding.ScrollView.getChildAt(0) + if (lastChild != null) { + val bottom: Int = + lastChild.bottom + binding.ScrollView.paddingBottom + binding.ScrollView.smoothScrollTo(0, bottom) + } else { + fullScroll(View.FOCUS_DOWN) + } + } + } + } + updateJumpButtonsVisibility() } binding.BottomAppBarRight.apply { removeAllViews() diff --git a/app/src/main/java/com/philkes/notallyx/presentation/activity/note/EditListActivity.kt b/app/src/main/java/com/philkes/notallyx/presentation/activity/note/EditListActivity.kt index 00f9836b..585d0576 100644 --- a/app/src/main/java/com/philkes/notallyx/presentation/activity/note/EditListActivity.kt +++ b/app/src/main/java/com/philkes/notallyx/presentation/activity/note/EditListActivity.kt @@ -241,11 +241,13 @@ class EditListActivity : EditActivity(Type.LIST), MoreListActions { endSearch() } }, - ) { _ -> - if (isInSearchMode() && search.results.value > 0) { - updateSearchResults(search.query) - } - } + { _ -> + if (isInSearchMode() && search.results.value > 0) { + updateSearchResults(search.query) + } + }, + { items -> updateJumpButtonsVisibility(items) }, + ) adapter = ListItemAdapter( colorInt, diff --git a/app/src/main/java/com/philkes/notallyx/presentation/activity/note/EditNoteActivity.kt b/app/src/main/java/com/philkes/notallyx/presentation/activity/note/EditNoteActivity.kt index c0eba2b0..a6487357 100644 --- a/app/src/main/java/com/philkes/notallyx/presentation/activity/note/EditNoteActivity.kt +++ b/app/src/main/java/com/philkes/notallyx/presentation/activity/note/EditNoteActivity.kt @@ -162,6 +162,7 @@ class EditNoteActivity : EditActivity(Type.NOTE), AddNoteActions { notallyModel.body = text if (textChanged) { updateSearchResults(search.query) + updateJumpButtonsVisibility() } } } diff --git a/app/src/main/java/com/philkes/notallyx/presentation/view/note/listitem/ListManager.kt b/app/src/main/java/com/philkes/notallyx/presentation/view/note/listitem/ListManager.kt index cbcbcad4..4b217ec8 100644 --- a/app/src/main/java/com/philkes/notallyx/presentation/view/note/listitem/ListManager.kt +++ b/app/src/main/java/com/philkes/notallyx/presentation/view/note/listitem/ListManager.kt @@ -3,7 +3,6 @@ package com.philkes.notallyx.presentation.view.note.listitem import android.util.Log import android.view.View import android.view.inputmethod.InputMethodManager -import android.widget.EditText import androidx.recyclerview.widget.RecyclerView import com.philkes.notallyx.data.model.ListItem import com.philkes.notallyx.data.model.check @@ -48,6 +47,7 @@ class ListManager( private val inputMethodManager: InputMethodManager?, private val endSearch: (() -> Unit)?, val refreshSearch: ((refocusView: View?) -> Unit)?, + val onItemSizeChanged: ((items: Int) -> Unit)?, ) { lateinit var adapter: ListItemAdapter var checkedAdapter: CheckedListItemAdapter? = null @@ -151,6 +151,7 @@ class ListManager( inputMethodManager?.let { viewHolder.focusEditText(inputMethodManager = it) } } } + onItemSizeChanged?.invoke(items.size + (itemsChecked?.size() ?: 0)) } /** @@ -201,6 +202,7 @@ class ListManager( if (pushChange && result) { changeHistory.push(ListDeleteChange(stateBefore, getState(), this)) } + onItemSizeChanged?.invoke(items.size + (itemsChecked?.size() ?: 0)) return result } @@ -372,6 +374,7 @@ class ListManager( if (pushChange) { changeHistory.push(DeleteCheckedChange(stateBefore, getState(), this)) } + onItemSizeChanged?.invoke(items.size + (itemsChecked?.size() ?: 0)) } fun findParent(item: ListItem) = items.findParent(item) ?: itemsChecked?.findParent(item) diff --git a/app/src/main/java/com/philkes/notallyx/utils/AndroidExtensions.kt b/app/src/main/java/com/philkes/notallyx/utils/AndroidExtensions.kt index 39e16f80..5f5be32e 100644 --- a/app/src/main/java/com/philkes/notallyx/utils/AndroidExtensions.kt +++ b/app/src/main/java/com/philkes/notallyx/utils/AndroidExtensions.kt @@ -246,6 +246,9 @@ fun Activity.showErrorDialog( .show() } +val Activity.isInLandscapeMode + get() = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE + private const val MAX_LOGS_FILE_SIZE_KB: Long = 2048 private fun Context.logToFile( diff --git a/app/src/main/res/drawable/vertical_align_bottom.xml b/app/src/main/res/drawable/vertical_align_bottom.xml new file mode 100644 index 00000000..2b404619 --- /dev/null +++ b/app/src/main/res/drawable/vertical_align_bottom.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/vertical_align_top.xml b/app/src/main/res/drawable/vertical_align_top.xml new file mode 100644 index 00000000..5cd27f8a --- /dev/null +++ b/app/src/main/res/drawable/vertical_align_top.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 61781f33..ad627fc4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -216,6 +216,8 @@ Item JSON Files 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. + Jump to bottom + Jump to top Label exists Hide/Show the label in the navigation panel Labels diff --git a/app/src/test/kotlin/com/philkes/notallyx/recyclerview/listmanager/ListManagerTestBase.kt b/app/src/test/kotlin/com/philkes/notallyx/recyclerview/listmanager/ListManagerTestBase.kt index 9e56209e..4f5edda2 100644 --- a/app/src/test/kotlin/com/philkes/notallyx/recyclerview/listmanager/ListManagerTestBase.kt +++ b/app/src/test/kotlin/com/philkes/notallyx/recyclerview/listmanager/ListManagerTestBase.kt @@ -59,7 +59,7 @@ open class ListManagerTestBase { listItemVH = mock(ListItemVH::class.java) preferences = mock(NotallyXPreferences::class.java) listManager = - ListManager(recyclerView, changeHistory, preferences, inputMethodManager, {}) {} + ListManager(recyclerView, changeHistory, preferences, inputMethodManager, {}, {}, null) // Prepare view holder `when`(recyclerView.findViewHolderForAdapterPosition(anyInt())).thenReturn(listItemVH) } diff --git a/app/translations.xlsx b/app/translations.xlsx index 294205ab..88cdb42b 100644 Binary files a/app/translations.xlsx and b/app/translations.xlsx differ