progress bar + material you title bar

This commit is contained in:
Kieran W 2023-08-23 23:11:36 +01:00
parent 04159344d7
commit d440ed33f3
7 changed files with 109 additions and 23 deletions

View File

@ -77,7 +77,6 @@ dependencies {
testImplementation("androidx.test.ext:junit:1.1.5") testImplementation("androidx.test.ext:junit:1.1.5")
testImplementation("androidx.test.espresso:espresso-core:3.5.1") testImplementation("androidx.test.espresso:espresso-core:3.5.1")
implementation("com.google.code.gson:gson:2.10.1") implementation("com.google.code.gson:gson:2.10.1")
} }
ktlint { ktlint {

View File

@ -16,6 +16,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.fredhappyface.ewesticker.utilities.Toaster import com.fredhappyface.ewesticker.utilities.Toaster
import com.google.android.material.progressindicator.LinearProgressIndicator
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -120,11 +121,13 @@ class MainActivity : AppCompatActivity() {
toaster.toast(getString(R.string.imported_010)) toaster.toast(getString(R.string.imported_010))
val button = findViewById<Button>(R.id.updateStickerPackInfoBtn) val button = findViewById<Button>(R.id.updateStickerPackInfoBtn)
val button2 = findViewById<Button>(R.id.reloadStickerPackInfoBtn) val button2 = findViewById<Button>(R.id.reloadStickerPackInfoBtn)
val progressBar = findViewById<LinearProgressIndicator>(R.id.linearProgressIndicator)
button.isEnabled = false button.isEnabled = false
button2.isEnabled = false button2.isEnabled = false
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
val totalStickers = StickerImporter(baseContext, toaster).importStickers(stickerDirPath) val totalStickers =
StickerImporter(baseContext, toaster, progressBar).importStickers(stickerDirPath)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
toaster.toastOnState( toaster.toastOnState(

View File

@ -2,9 +2,13 @@ package com.fredhappyface.ewesticker
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import android.os.Handler
import android.os.Looper
import android.view.View
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import com.fredhappyface.ewesticker.utilities.Toaster import com.fredhappyface.ewesticker.utilities.Toaster
import com.fredhappyface.ewesticker.utilities.Utils import com.fredhappyface.ewesticker.utilities.Utils
import com.google.android.material.progressindicator.LinearProgressIndicator
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll import kotlinx.coroutines.awaitAll
@ -28,11 +32,19 @@ private const val BUFFER_SIZE = 64 * 1024 // 64 KB
class StickerImporter( class StickerImporter(
private val context: Context, private val context: Context,
private val toaster: Toaster, private val toaster: Toaster,
private val progressBar: LinearProgressIndicator,
) { ) {
private val supportedMimes = Utils.getSupportedMimes() private val supportedMimes = Utils.getSupportedMimes()
private val packSizes: MutableMap<String, Int> = mutableMapOf() private val packSizes: MutableMap<String, Int> = mutableMapOf()
private var totalStickers = 0 private var totalStickers = 0
private val mainHandler = Handler(Looper.getMainLooper())
private fun updateProgressBar(currentProgress: Int, totalStickers: Int) {
val progressPercentage = (currentProgress.toFloat() / totalStickers.toFloat()) * 100
progressBar.progress = progressPercentage.toInt()
}
/** /**
* Used by the ACTION_OPEN_DOCUMENT_TREE handler function to copy stickers from a * Used by the ACTION_OPEN_DOCUMENT_TREE handler function to copy stickers from a
@ -43,18 +55,37 @@ class StickerImporter(
*/ */
suspend fun importStickers(stickerDirPath: String): Int { suspend fun importStickers(stickerDirPath: String): Int {
File(context.filesDir, "stickers").deleteRecursively() File(context.filesDir, "stickers").deleteRecursively()
withContext(Dispatchers.Main) {
progressBar.visibility = View.VISIBLE
progressBar.isIndeterminate = true
}
val leafNodes = fileWalk(DocumentFile.fromTreeUri(context, Uri.parse(stickerDirPath))) val leafNodes = fileWalk(DocumentFile.fromTreeUri(context, Uri.parse(stickerDirPath)))
if (leafNodes.size > MAX_FILES) { if (leafNodes.size > MAX_FILES) {
toaster.setState(1) toaster.setState(1)
} }
withContext(Dispatchers.Main) {
progressBar.isIndeterminate = false
}
// Perform concurrent file copy operations // Perform concurrent file copy operations
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
leafNodes.take(MAX_FILES).map { file -> leafNodes.take(MAX_FILES).mapIndexed { index, file ->
async { importSticker(file) } async {
importSticker(file)
mainHandler.post {
updateProgressBar(index + 1, leafNodes.size)
}
}
}.awaitAll() }.awaitAll()
} }
withContext(Dispatchers.Main) {
progressBar.visibility = View.GONE
}
return leafNodes.size return leafNodes.size
} }
@ -107,18 +138,24 @@ class StickerImporter(
*/ */
private fun fileWalk(rootNode: DocumentFile?): Set<DocumentFile> { private fun fileWalk(rootNode: DocumentFile?): Set<DocumentFile> {
val leafNodes = mutableSetOf<DocumentFile>() val leafNodes = mutableSetOf<DocumentFile>()
if (rootNode == null || totalStickers >= MAX_FILES) { val stack = ArrayDeque<DocumentFile?>()
return leafNodes
} rootNode?.let { stack.addLast(it) }
rootNode.listFiles().forEach { file ->
if (file.isFile) { while (stack.isNotEmpty() && leafNodes.size < MAX_FILES) {
leafNodes.add(file) val currentFile = stack.removeLast()
totalStickers++
} else if (file.isDirectory) { currentFile?.listFiles()?.forEach { file ->
leafNodes.addAll(fileWalk(file)) if (file.isFile) {
} leafNodes.add(file)
if (totalStickers >= MAX_FILES) { totalStickers++
return@forEach
if (leafNodes.size >= MAX_FILES) {
return leafNodes
}
} else if (file.isDirectory) {
stack.addLast(file)
}
} }
} }
return leafNodes return leafNodes

View File

@ -1,15 +1,48 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.circularreveal.coordinatorlayout.CircularRevealCoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activityMainRoot" android:id="@+id/activityMainRoot"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@color/bg"> android:background="@color/bg">
<ScrollView <com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/accent">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsingToolbarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
android:background="@color/accent"
app:collapsedTitleTextAppearance="@style/ToolbarTitleTextAppearance"
app:expandedTitleTextAppearance="@style/ToolbarTitleTextAppearance"
app:title=" EweSticker">
<View
android:layout_width="match_parent"
android:layout_height="@dimen/appbar_padding"
android:background="@color/accent" />
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="none"
app:layout_collapseParallaxMultiplier="0.7"
android:background="@color/accent" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout <LinearLayout
style="@style/widthMatchHeightWrap" style="@style/widthMatchHeightWrap"
@ -111,6 +144,13 @@
android:onClick="reloadStickers" android:onClick="reloadStickers"
android:text="@string/reload_sticker_pack_button" android:text="@string/reload_sticker_pack_button"
app:shapeAppearance="?attr/shapeAppearanceSmallComponent" /> app:shapeAppearance="?attr/shapeAppearanceSmallComponent" />
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/linearProgressIndicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
</LinearLayout> </LinearLayout>
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>
<!-- Options --> <!-- Options -->
@ -292,5 +332,5 @@
</LinearLayout> </LinearLayout>
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>
</LinearLayout> </LinearLayout>
</ScrollView> </androidx.core.widget.NestedScrollView>
</com.google.android.material.circularreveal.coordinatorlayout.CircularRevealCoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="AppTheme" parent="Theme.Material3.DayNight"> <style name="AppTheme" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Primary brand color. --> <!-- Primary brand color. -->
<item name="colorPrimaryVariant">@color/accent</item> <item name="colorPrimaryVariant">@color/accent</item>
<item name="colorOnPrimary">@color/onAccent</item> <item name="colorOnPrimary">@color/onAccent</item>

View File

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<dimen name="r_btn">32sp</dimen> <dimen name="r_btn">32sp</dimen>
<dimen name="appbar_padding">160dp</dimen>
<dimen name="text_size_title">36sp</dimen>
<dimen name="text_size_heading">24sp</dimen> <dimen name="text_size_heading">24sp</dimen>
<dimen name="text_size_body">16sp</dimen> <dimen name="text_size_body">16sp</dimen>
<dimen name="content_margin">10dp</dimen> <dimen name="content_margin">10dp</dimen>

View File

@ -1,6 +1,6 @@
<resources> <resources>
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="AppTheme" parent="Theme.Material3.DayNight"> <style name="AppTheme" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Primary brand color. --> <!-- Primary brand color. -->
<item name="colorPrimaryVariant">@color/accent</item> <item name="colorPrimaryVariant">@color/accent</item>
<item name="colorOnPrimary">@color/onAccent</item> <item name="colorOnPrimary">@color/onAccent</item>
@ -23,6 +23,11 @@
<item name="shapeAppearanceSmallComponent">@style/ShapeAppearance.App.SmallComponent</item> <item name="shapeAppearanceSmallComponent">@style/ShapeAppearance.App.SmallComponent</item>
</style> </style>
<style name="ToolbarTitleTextAppearance" parent="@style/TextAppearance.Widget.AppCompat.Toolbar.Title">
<item name="android:textSize">@dimen/text_size_title</item>
</style>
<style name="ShapeAppearance.App.MediumComponent" parent="ShapeAppearance.MaterialComponents.MediumComponent"> <style name="ShapeAppearance.App.MediumComponent" parent="ShapeAppearance.MaterialComponents.MediumComponent">
<item name="cornerSize">@dimen/corner</item> <item name="cornerSize">@dimen/corner</item>
</style> </style>