diff --git a/.kotlin/errors/errors-1781080840517.log b/.kotlin/errors/errors-1781080840517.log new file mode 100644 index 0000000..dfd545e --- /dev/null +++ b/.kotlin/errors/errors-1781080840517.log @@ -0,0 +1,73 @@ +kotlin version: 2.1.21 +error message: Daemon compilation failed: null +java.lang.Exception + at org.jetbrains.kotlin.daemon.common.CompileService$CallResult$Error.get(CompileService.kt:69) + at org.jetbrains.kotlin.daemon.common.CompileService$CallResult$Error.get(CompileService.kt:65) + at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:240) + at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159) + at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111) + at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:76) + at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:63) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:66) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:62) + at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:100) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:62) + at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44) + at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41) + at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209) + at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59) + at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53) + at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:59) + at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:174) + at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169) + at org.gradle.internal.Factories$1.create(Factories.java:31) + at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:263) + at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127) + at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133) + at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572) + at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317) + at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) + at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:48) + at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) + at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) + at java.base/java.lang.Thread.run(Thread.java:1583) +Caused by: java.nio.file.NoSuchFileException: /tmp/kotlin-backups9429064796643384370/222.backup -> /home/shihaam/git/sargit/thijooree/app/build/tmp/kotlin-classes/debug/sh/sar/basedbank/ui/home/TransferFragment$lookupAccount$1.class + at java.base/sun.nio.fs.UnixException.translateToIOException(Unknown Source) + at java.base/sun.nio.fs.UnixException.rethrowAsIOException(Unknown Source) + at java.base/sun.nio.fs.UnixFileSystem.move(Unknown Source) + at java.base/sun.nio.fs.UnixFileSystemProvider.move(Unknown Source) + at java.base/java.nio.file.Files.move(Unknown Source) + at org.jetbrains.kotlin.incremental.RecoverableCompilationTransaction.revertChanges(CompilationTransaction.kt:231) + at org.jetbrains.kotlin.incremental.RecoverableCompilationTransaction.close(CompilationTransaction.kt:256) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.tryCompileIncrementally(IncrementalCompilerRunner.kt:762) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:128) + at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:678) + at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:92) + at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1805) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source) + at java.base/java.lang.reflect.Method.invoke(Unknown Source) + at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(Unknown Source) + at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source) + at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source) + at java.base/java.security.AccessController.doPrivileged(Unknown Source) + at java.rmi/sun.rmi.transport.Transport.serviceCall(Unknown Source) + at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source) + at java.base/java.security.AccessController.doPrivileged(Unknown Source) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source) + at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) + at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) + at java.base/java.lang.Thread.run(Unknown Source) + + diff --git a/app/src/main/java/sh/sar/basedbank/ui/home/NotificationsSheetFragment.kt b/app/src/main/java/sh/sar/basedbank/ui/home/NotificationsSheetFragment.kt index 83b0cfc..83d23d3 100644 --- a/app/src/main/java/sh/sar/basedbank/ui/home/NotificationsSheetFragment.kt +++ b/app/src/main/java/sh/sar/basedbank/ui/home/NotificationsSheetFragment.kt @@ -13,10 +13,12 @@ import android.view.ViewGroup import android.widget.FrameLayout import android.widget.ImageView import android.widget.LinearLayout +import android.widget.ProgressBar import android.widget.TextView import android.widget.Toast import androidx.core.view.isVisible import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.widget.ViewPager2 @@ -62,6 +64,23 @@ private fun toGroupedList(notifications: List): List, + private val new: List +) : DiffUtil.Callback() { + override fun getOldListSize() = old.size + override fun getNewListSize() = new.size + override fun areItemsTheSame(oldPos: Int, newPos: Int): Boolean { + val o = old[oldPos]; val n = new[newPos] + return when { + o is NotifListItem.Header && n is NotifListItem.Header -> o.label == n.label + o is NotifListItem.Entry && n is NotifListItem.Entry -> o.n.id == n.n.id + else -> false + } + } + override fun areContentsTheSame(oldPos: Int, newPos: Int) = old[oldPos] == new[newPos] +} + class NotificationsSheetFragment : BottomSheetDialogFragment() { var onUnreadCountChanged: ((hasUnread: Boolean) -> Unit)? = null @@ -148,11 +167,16 @@ class NotificationsSheetFragment : BottomSheetDialogFragment() { } } + private fun setSpinner(show: Boolean) { + tabAdapters.forEach { it?.showLoadingSpinner = show } + } + private fun refreshFromNetwork() { val bmlSessions = app.bmlSessions.toMap() val mibSessions = app.mibSessions.toMap() lifecycleScope.launch { + setSpinner(true) val bmlClient = BmlNotificationsClient() bmlSessions.forEach { (loginId, session) -> val result = withContext(Dispatchers.IO) { @@ -196,6 +220,8 @@ class NotificationsSheetFragment : BottomSheetDialogFragment() { mibDone[loginId] = hasOverlap || result.nextStart > result.totalCount } } + + if (isAdded) setSpinner(false) } } @@ -208,6 +234,7 @@ class NotificationsSheetFragment : BottomSheetDialogFragment() { if (!anyLeft) return isLoadingMore = true + setSpinner(true) lifecycleScope.launch { val bmlClient = BmlNotificationsClient() bmlSessions.forEach { (loginId, session) -> @@ -255,7 +282,10 @@ class NotificationsSheetFragment : BottomSheetDialogFragment() { } isLoadingMore = false - if (isAdded) refreshAdapters() + if (isAdded) { + setSpinner(false) + refreshAdapters() + } } } @@ -359,16 +389,35 @@ class NotificationsSheetFragment : BottomSheetDialogFragment() { private val displayItems = mutableListOf() + var showLoadingSpinner: Boolean = false + set(value) { + if (field == value) return + field = value + if (displayItems.isEmpty()) { + notifyItemChanged(0) + } else if (value) { + notifyItemInserted(displayItems.size) + } else { + notifyItemRemoved(displayItems.size) + } + } + fun update(filtered: List) { + val newItems = toGroupedList(filtered) + val diff = DiffUtil.calculateDiff(NotifDiff(displayItems.toList(), newItems)) displayItems.clear() - displayItems.addAll(toGroupedList(filtered)) - notifyDataSetChanged() + displayItems.addAll(newItems) + diff.dispatchUpdatesTo(this) } - override fun getItemCount() = if (displayItems.isEmpty()) 1 else displayItems.size + override fun getItemCount(): Int { + if (displayItems.isEmpty()) return 1 + return displayItems.size + if (showLoadingSpinner) 1 else 0 + } override fun getItemViewType(position: Int): Int { - if (displayItems.isEmpty()) return 2 // empty + if (displayItems.isEmpty()) return if (showLoadingSpinner) 3 else 2 + if (showLoadingSpinner && position == displayItems.size) return 3 return when (displayItems[position]) { is NotifListItem.Header -> 0 is NotifListItem.Entry -> 1 @@ -379,6 +428,7 @@ class NotificationsSheetFragment : BottomSheetDialogFragment() { when (viewType) { 0 -> HeaderVH(buildHeaderView(parent.context)) 1 -> ItemVH(buildRowView(parent.context)) + 3 -> SpinnerVH(buildSpinnerView(parent.context)) else -> EmptyVH(buildEmptyView(parent.context)) } @@ -439,6 +489,28 @@ class NotificationsSheetFragment : BottomSheetDialogFragment() { } } + // ── Loading spinner ─────────────────────────────────────────────────────── + + inner class SpinnerVH(v: View) : RecyclerView.ViewHolder(v) + + private fun buildSpinnerView(ctx: android.content.Context): View { + val dp = ctx.resources.displayMetrics.density + val pad = (16 * dp).toInt() + val size = (28 * dp).toInt() + return LinearLayout(ctx).apply { + orientation = LinearLayout.VERTICAL + gravity = Gravity.CENTER + layoutParams = ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + setPadding(pad, pad, pad, pad) + addView(ProgressBar(ctx).apply { + layoutParams = LinearLayout.LayoutParams(size, size) + }) + } + } + // ── Notification row ────────────────────────────────────────────────────── inner class ItemVH(v: View) : RecyclerView.ViewHolder(v) {