diff --git a/.github/workflows/android-test.yml b/.github/workflows/android-test.yml new file mode 100644 index 00000000..e499e2f5 --- /dev/null +++ b/.github/workflows/android-test.yml @@ -0,0 +1,99 @@ +name: Android Emulator Tests +on: [ push, pull_request ] + +jobs: + check-if-tests-exist: + runs-on: ubuntu-latest + outputs: + status: ${{ steps.check-androidTest.outputs.NOT_EMPTY }} + min-sdk-version: ${{ steps.get-sdk-version.outputs.MIN_SDK_VERSION }} + target-sdk-version: ${{ steps.get-sdk-version.outputs.TARGET_SDK_VERSION }} + app-id: ${{ steps.get-app-id.outputs.APP_ID }} + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: "recursive" + - name: Check if androidTest folder is not empty + run: | + echo "NOT_EMPTY=$([ "$(ls -A app/src/androidTest)" ] && echo 'true' || echo 'false')" + echo "NOT_EMPTY=$([ "$(ls -A app/src/androidTest)" ] && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT + id: check-androidTest + - name: Get min and target sdk + if: steps.check-androidTest.outputs.NOT_EMPTY == 'true' + id: get-sdk-version + run: | + echo "MIN_SDK_VERSION=$(cat app/build.gradle | grep minSdkVersion | rev | cut -d' ' -f 1 | rev)" >> $GITHUB_OUTPUT + echo "TARGET_SDK_VERSION=$(cat app/build.gradle | grep targetSdkVersion | rev | cut -d' ' -f 1 | rev)" >> $GITHUB_OUTPUT + - name: Get app ID + id: get-app-id + run: | + echo "APP_ID=$(cat app/build.gradle | grep applicationId | rev | cut -d' ' -f 1 | rev | tr -d '"')" >> $GITHUB_OUTPUT + + test: + needs: check-if-tests-exist + if: needs.check-if-tests-exist.outputs.status == 'true' + runs-on: ubuntu-latest + strategy: + matrix: + api-level: [34, "${{ needs.check-if-tests-exist.outputs.min-sdk-version }}", "${{ needs.check-if-tests-exist.outputs.target-sdk-version }}"] + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: 'recursive' + + - name: Enable KVM group perms + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + + - name: Gradle cache + uses: gradle/gradle-build-action@v3 + + - name: AVD cache + uses: actions/cache@v4 + id: avd-cache + with: + path: | + ~/.android/avd/* + ~/.android/adb* + key: avd-${{ matrix.api-level }} + + - name: Set up JDK environment + uses: actions/setup-java@v3 + with: + distribution: 'zulu' + java-version: 17 + + - name: create AVD and generate snapshot for caching + if: steps.avd-cache.outputs.cache-hit != 'true' + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: ${{ matrix.api-level }} + target: ${{ matrix.api-level >= 30 && 'google_apis' || 'default' }} + arch: ${{ matrix.api-level < 21 && 'x86' || 'x86_64' }} + force-avd-creation: false + emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + disable-animations: false + script: echo "Generated AVD snapshot for caching." + + - name: Run connected tests + uses: ReactiveCircus/android-emulator-runner@v2 + with: + api-level: ${{ matrix.api-level }} + target: ${{ matrix.api-level >= 30 && 'google_apis' || 'default' }} + arch: ${{ matrix.api-level < 21 && 'x86' || 'x86_64' }} + force-avd-creation: false + emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + disable-animations: true + script: | + adb uninstall ${{needs.check-if-tests-exist.outputs.app-id}} || true + adb uninstall ${{needs.check-if-tests-exist.outputs.app-id}}.test || true + adb uninstall ${{needs.check-if-tests-exist.outputs.app-id}}.androidTest || true + chmod +x gradlew + ./gradlew :app:connectedCheck --stacktrace + adb uninstall ${{needs.check-if-tests-exist.outputs.app-id}} || true + adb uninstall ${{needs.check-if-tests-exist.outputs.app-id}}.test || true + adb uninstall ${{needs.check-if-tests-exist.outputs.app-id}}.androidTest || true diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index b20a40da..6e50db11 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -2,7 +2,7 @@ name: Changelog Generation on: release: - types: [released] + types: [published] workflow_dispatch: jobs: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 694228ee..fe5b0a92 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,55 +1,32 @@ -name: Continuous integration - +name: Continuous Integration on: [push, pull_request] jobs: test: - name: Unit Tests runs-on: ubuntu-20.04 steps: - name: Checkout uses: actions/checkout@v3 with: submodules: "recursive" + - name: Set up JDK environment uses: actions/setup-java@v3 with: distribution: "zulu" java-version: 17 + - name: Make gradlew executable run: chmod +x ./gradlew + - name: Setup Gradle uses: gradle/gradle-build-action@v2 + - name: Run local unit tests run: bash ./gradlew test --stacktrace - - name: Android Test Report - uses: asadmansr/android-test-report-action@v1.2.0 - - #androidTest: - # name: Instrumented Tests - # runs-on: macOS-latest - # steps: - # - uses: actions/checkout@v2 - # with: - # submodules: 'recursive' - # - name: Set up JDK 1.8 - # uses: actions/setup-java@v1 - # with: - # java-version: 1.8 - # - name: Make gradlew executable - # run: chmod +x ./gradlew - # - name: Run Instrumented Tests - # uses: reactivecircus/android-emulator-runner@v1 - # with: - # api-level: 29 - # arch: x86 - # disable-animations: true - # script: ./gradlew connectedAndroidTest --stacktrace - apk: - name: Build APK + build: runs-on: ubuntu-20.04 - steps: - name: Checkout uses: actions/checkout@v3 @@ -68,5 +45,23 @@ jobs: - name: Setup Gradle uses: gradle/gradle-build-action@v2 - - name: Build debug APK - run: ./gradlew assembleDebug + - name: Run lint check + run: bash ./gradlew lint + + - name: Upload lint result + uses: actions/upload-artifact@v4 + with: + name: lint-results-debug + path: app/build/reports/lint-results-debug.html + + - name: Build the app + run: bash ./gradlew build --stacktrace + + - name: Build debug apk + run: bash ./gradlew assembleDebug + + - name: Upload debug apk + uses: actions/upload-artifact@v4 + with: + name: debug-apk + path: app/build/outputs/apk/debug/*.apk \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 185b8a90..ae8e3c3f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -24,8 +24,8 @@ android { minSdkVersion 21 compileSdk 34 targetSdkVersion 34 - versionCode 19 - versionName "2.0.0" + versionCode 20 + versionName "2.0.1" } applicationVariants.configureEach { variant -> @@ -58,6 +58,10 @@ android { jvmTarget = JavaVersion.VERSION_17.toString() } + lint { + lintConfig = file("lint.xml") + } + room { schemaDirectory "$projectDir/schemas" } @@ -82,6 +86,7 @@ dependencies { implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation "androidx.constraintlayout:constraintlayout:2.1.4" implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1' + implementation 'com.github.bumptech.glide:glide:4.11.0' def work_version = "2.8.1" implementation "androidx.work:work-runtime:$work_version" diff --git a/app/lint.xml b/app/lint.xml new file mode 100644 index 00000000..1b66a254 --- /dev/null +++ b/app/lint.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/RecycleActivity.kt b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/RecycleActivity.kt index 823ff7b2..5174d802 100644 --- a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/RecycleActivity.kt +++ b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/RecycleActivity.kt @@ -14,7 +14,6 @@ package org.secuso.privacyfriendlynotes.ui import android.os.Bundle -import androidx.preference.PreferenceManager import android.view.ContextThemeWrapper import android.view.Menu import android.view.MenuItem @@ -24,6 +23,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope +import androidx.preference.PreferenceManager import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView @@ -43,7 +43,7 @@ import org.secuso.privacyfriendlynotes.ui.main.MainActivityViewModel class RecycleActivity : AppCompatActivity() { private val mainActivityViewModel: MainActivityViewModel by lazy { ViewModelProvider(this)[MainActivityViewModel::class.java] } private val searchView: SearchView by lazy { findViewById(R.id.searchViewFilterRecycle) } - private val adapter: NoteAdapter by lazy { NoteAdapter(mainActivityViewModel, true) } + private val adapter: NoteAdapter by lazy { NoteAdapter(this, mainActivityViewModel, true) } private val trashedNotes by lazy { mainActivityViewModel.trashedNotes.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED).stateIn(lifecycleScope, SharingStarted.Lazily, listOf()) } diff --git a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/adapter/NoteAdapter.kt b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/adapter/NoteAdapter.kt index de0a76f6..b96fd394 100644 --- a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/adapter/NoteAdapter.kt +++ b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/adapter/NoteAdapter.kt @@ -13,8 +13,8 @@ */ package org.secuso.privacyfriendlynotes.ui.adapter +import android.app.Activity import android.graphics.Color -import android.preference.PreferenceManager import android.text.Html import android.util.TypedValue import android.view.LayoutInflater @@ -22,12 +22,16 @@ import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView +import androidx.appcompat.content.res.AppCompatResources +import androidx.preference.PreferenceManager import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide import org.secuso.privacyfriendlynotes.R import org.secuso.privacyfriendlynotes.room.DbContract import org.secuso.privacyfriendlynotes.room.model.Note import org.secuso.privacyfriendlynotes.ui.main.MainActivityViewModel import org.secuso.privacyfriendlynotes.ui.util.DarkModeUtil +import java.io.File /** * Adapter that provides a binding for notes @@ -36,6 +40,7 @@ import org.secuso.privacyfriendlynotes.ui.util.DarkModeUtil * @see org.secuso.privacyfriendlynotes.ui.RecycleActivity */ class NoteAdapter( + private val activity: Activity, private val mainActivityViewModel: MainActivityViewModel, var colorCategory: Boolean, ) : RecyclerView.Adapter() { @@ -62,7 +67,8 @@ class NoteAdapter( holder.textViewTitle.text = currentNote.name holder.textViewDescription.text = "" val pref = PreferenceManager.getDefaultSharedPreferences(holder.itemView.context) - holder.textViewDescription.visibility = if (pref.getBoolean("settings_show_preview", true)) View.VISIBLE else View.GONE + val showPreview = pref.getBoolean("settings_show_preview", true) + holder.textViewDescription.visibility = if (showPreview) View.VISIBLE else View.GONE holder.textViewExtraText.visibility = View.GONE holder.textViewExtraText.text = null holder.imageViewcategory.visibility = View.GONE @@ -94,45 +100,50 @@ class NoteAdapter( } } - when (currentNote.type) { - DbContract.NoteEntry.TYPE_TEXT -> { - holder.textViewDescription.text = Html.fromHtml(currentNote.content) - holder.textViewDescription.maxLines = 3 - } + when (currentNote.type) { + DbContract.NoteEntry.TYPE_TEXT -> { + if (showPreview) { + holder.textViewDescription.text = Html.fromHtml(currentNote.content) + holder.textViewDescription.maxLines = 3 + } + } - DbContract.NoteEntry.TYPE_AUDIO -> { - holder.imageViewcategory.visibility = View.VISIBLE - holder.imageViewcategory.setImageResource(R.drawable.ic_mic_icon_24dp) - } + DbContract.NoteEntry.TYPE_AUDIO -> { + holder.imageViewcategory.visibility = View.VISIBLE + holder.imageViewcategory.setImageResource(R.drawable.ic_mic_icon_24dp) + } - DbContract.NoteEntry.TYPE_SKETCH -> { - holder.imageViewcategory.visibility = View.VISIBLE - holder.imageViewcategory.setBackgroundColor(run { - val value = TypedValue() - holder.itemView.context.theme.resolveAttribute(R.attr.colorSurfaceVariantLight, value, true) - value.data - }) - if (pref.getBoolean("settings_show_preview", true)) { - val bitmap = mainActivityViewModel.sketchPreview(currentNote, 200) - if (bitmap != null) { - holder.imageViewcategory.setImageBitmap(mainActivityViewModel.sketchPreview(currentNote, 200)) + DbContract.NoteEntry.TYPE_SKETCH -> { + holder.imageViewcategory.visibility = View.VISIBLE + if (showPreview) { + holder.imageViewcategory.setBackgroundColor(run { + val value = TypedValue() + holder.itemView.context.theme.resolveAttribute(R.attr.colorSurfaceVariantLight, value, true) + value.data + }) + holder.imageViewcategory.minimumHeight = 200; holder.imageViewcategory.minimumWidth = 200 + Glide.with(activity).load(File("${activity.application.filesDir.path}/sketches${currentNote.content}")) + .placeholder(AppCompatResources.getDrawable(activity, R.drawable.ic_photo_icon_24dp)) + .into(holder.imageViewcategory) } else { holder.imageViewcategory.setImageResource(R.drawable.ic_photo_icon_24dp) } - } else { - holder.imageViewcategory.setImageResource(R.drawable.ic_photo_icon_24dp) } - } - DbContract.NoteEntry.TYPE_CHECKLIST -> { - val preview = mainActivityViewModel.checklistPreview(currentNote) - holder.textViewExtraText.text = "${preview.filter { it.first }.count()}/${preview.size}" - holder.textViewExtraText.visibility = View.VISIBLE - holder.imageViewcategory.visibility = View.GONE - holder.textViewDescription.text = preview.take(3).joinToString(System.lineSeparator()) { it.second } - holder.textViewDescription.maxLines = 3 + DbContract.NoteEntry.TYPE_CHECKLIST -> { + holder.imageViewcategory.visibility = View.GONE + holder.textViewExtraText.visibility = View.VISIBLE + + if (showPreview) { + val preview = mainActivityViewModel.checklistPreview(currentNote) + holder.textViewExtraText.text = "${preview.filter { it.first }.count()}/${preview.size}" + holder.textViewDescription.text = preview.take(3).joinToString(System.lineSeparator()) { it.second } + holder.textViewDescription.maxLines = 3 + } else { + holder.textViewExtraText.text = "-/-" + } + } } - } // if the Description is empty, don't show it if (holder.textViewDescription.text.toString().isEmpty()) { diff --git a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/main/MainActivity.kt b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/main/MainActivity.kt index 9459c026..493f6666 100644 --- a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/main/MainActivity.kt +++ b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/main/MainActivity.kt @@ -91,7 +91,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte ActivityResultContracts.StartActivityForResult() ) { result: ActivityResult -> val data = result.data - if (result.resultCode == RESULT_OK && data != null) { + if (result.resultCode == RESULT_OK && data != null && data.hasExtra(BaseNoteActivity.EXTRA_CATEGORY)) { mainActivityViewModel.setCategory(data.getIntExtra(BaseNoteActivity.EXTRA_CATEGORY, CAT_ALL)) } fab.close() @@ -103,7 +103,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte if (className == MainFABFragment::class.java.name) { this@MainActivity.fab = MainFABFragment { Log.d("Received", "$it") - Intent( + val i = Intent( application, when (it) { DbContract.NoteEntry.TYPE_TEXT -> TextNoteActivity::class.java DbContract.NoteEntry.TYPE_CHECKLIST -> ChecklistNoteActivity::class.java @@ -111,7 +111,9 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte DbContract.NoteEntry.TYPE_SKETCH -> SketchActivity::class.java else -> throw NotImplementedError("Note of type $it cannot be created") } - ).let { intent -> setCategoryResultAfter.launch(intent) } + ) + i.putExtra(BaseNoteActivity.EXTRA_CATEGORY, mainActivityViewModel.getCategory()) + setCategoryResultAfter.launch(i) fab.close() } return fab @@ -137,6 +139,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte recyclerView.layoutManager = LinearLayoutManager(this) recyclerView.setHasFixedSize(true) adapter = NoteAdapter( + this, mainActivityViewModel, PreferenceManager.getDefaultSharedPreferences(this).getBoolean("settings_color_category", true) && mainActivityViewModel.getCategory() == CAT_ALL @@ -327,25 +330,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte return true } - /** - * Handles when notes are added. - * @param v - */ override fun onClick(v: View) { - val intent = - Function { activity: Class? -> - val i = Intent(application, activity) - i.putExtra(BaseNoteActivity.EXTRA_CATEGORY, mainActivityViewModel.getCategory()) - i - } - var i: Intent? = null - when (v.id) { - R.id.fab_text -> i = intent.apply(TextNoteActivity::class.java) - R.id.fab_checklist -> i = intent.apply(ChecklistNoteActivity::class.java) - R.id.fab_audio -> i = intent.apply(AudioNoteActivity::class.java) - R.id.fab_sketch -> i = intent.apply(SketchActivity::class.java) - } - setCategoryResultAfter.launch(i) } override fun onPause() { diff --git a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/main/MainActivityViewModel.kt b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/main/MainActivityViewModel.kt index c8bfcd41..521780f8 100644 --- a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/main/MainActivityViewModel.kt +++ b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/main/MainActivityViewModel.kt @@ -54,7 +54,9 @@ class MainActivityViewModel(application: Application) : AndroidViewModel(applica private val repository: NoteDatabase = NoteDatabase.getInstance(application) private var filter: MutableStateFlow = MutableStateFlow("") private var ordering: MutableStateFlow = MutableStateFlow( - SortingOrder.valueOf(prefManager.getString(PreferenceKeys.SP_NOTES_ORDERING, SortingOrder.AlphabeticalAscending.name)!!) + kotlin.runCatching { + SortingOrder.valueOf(prefManager.getString(PreferenceKeys.SP_NOTES_ORDERING, SortingOrder.AlphabeticalAscending.name)!!) + }.getOrElse { SortingOrder.AlphabeticalAscending } ) private var reversed: MutableStateFlow = MutableStateFlow( prefManager.getBoolean(PreferenceKeys.SP_NOTES_REVERSED, false) @@ -161,16 +163,16 @@ class MainActivityViewModel(application: Application) : AndroidViewModel(applica private fun Flow>.filterNotes(): Flow> { return this.map { it.filter { note -> - if (note.name.contains(filter.value)) { + if (note.name.contains(filter.value, ignoreCase = true)) { return@filter true } when (note.type) { DbContract.NoteEntry.TYPE_TEXT -> { - return@filter Html.fromHtml(note.content).toString().contains(filter.value) + return@filter Html.fromHtml(note.content).toString().contains(filter.value, ignoreCase = true) } DbContract.NoteEntry.TYPE_CHECKLIST -> { - return@filter ChecklistUtil.parse(note.content).joinToString(System.lineSeparator()).contains(filter.value) + return@filter ChecklistUtil.parse(note.content).joinToString(System.lineSeparator()).contains(filter.value, ignoreCase = true) } else -> return@filter false @@ -185,7 +187,11 @@ class MainActivityViewModel(application: Application) : AndroidViewModel(applica private fun Flow>.filterCategories(): Flow> { return this.map { - it.filter { note -> note.category == category.value || category.value == CAT_ALL } + it.filter { note -> + note.category == category.value // Note matches current category + || category.value == CAT_ALL // We're in the all notes category + || (category.value == 0 && note.category == -1) // Note is still in old default category (-1). Should still show in new default category (0) + } } } @@ -239,7 +245,7 @@ class MainActivityViewModel(application: Application) : AndroidViewModel(applica throw IllegalArgumentException("Only checklist notes allowed") } return ChecklistUtil.parse(note.content).map { (checked, name) -> - return@map Pair(checked, String.format("[%s] $name", if (checked) "x" else " ")) + return@map Pair(checked, "[${if (checked) "x" else " "}] $name") } } diff --git a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/notes/BaseNoteActivity.kt b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/notes/BaseNoteActivity.kt index e4fc22af..8e9e76ca 100644 --- a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/notes/BaseNoteActivity.kt +++ b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/notes/BaseNoteActivity.kt @@ -36,7 +36,14 @@ import android.view.MotionEvent import android.view.View import android.view.WindowManager import android.view.inputmethod.InputMethodManager -import android.widget.* +import android.widget.ArrayAdapter +import android.widget.AutoCompleteTextView +import android.widget.DatePicker +import android.widget.EditText +import android.widget.PopupMenu +import android.widget.TextView +import android.widget.TimePicker +import android.widget.Toast import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity @@ -47,6 +54,7 @@ import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import com.google.android.material.dialog.MaterialAlertDialogBuilder import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import org.secuso.privacyfriendlynotes.R import org.secuso.privacyfriendlynotes.preference.PreferenceKeys import org.secuso.privacyfriendlynotes.room.DbContract @@ -59,7 +67,8 @@ import org.secuso.privacyfriendlynotes.ui.helper.NotificationHelper.removeNotifi import org.secuso.privacyfriendlynotes.ui.helper.NotificationHelper.showAlertScheduledToast import org.secuso.privacyfriendlynotes.ui.manageCategories.ManageCategoriesActivity import java.io.OutputStream -import java.util.* +import java.util.Calendar +import java.util.Date /** * A abstract note. @@ -159,12 +168,13 @@ abstract class BaseNoteActivity(noteType: Int) : AppCompatActivity(), View.OnCli } - val intent = intent currentCat = intent.getIntExtra(EXTRA_CATEGORY, 0) savedCat = currentCat // Return the given intent as result to return to the same category as started - setResult(Activity.RESULT_OK, intent) + val resultIntent = Intent() + resultIntent.putExtra(EXTRA_CATEGORY, currentCat) + setResult(Activity.RESULT_OK, resultIntent) createEditNoteViewModel.getCategoryNameFromId(currentCat).observe(this) { s -> catSelection.setText(s ?: getString(R.string.default_category), false) @@ -463,7 +473,14 @@ abstract class BaseNoteActivity(noteType: Int) : AppCompatActivity(), View.OnCli } if (isLoadedNote) { note._id = id - createEditNoteViewModel.update(note) + if (showNotSaved) { + //Wait for job to complete + runBlocking { + createEditNoteViewModel.update(note).join() + } + } else { + createEditNoteViewModel.update(note) + } Toast.makeText(applicationContext, R.string.toast_updated, Toast.LENGTH_SHORT).show() } else { id = createEditNoteViewModel.insert(note) diff --git a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/notes/CreateEditNoteViewModel.kt b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/notes/CreateEditNoteViewModel.kt index e091a453..115953e9 100644 --- a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/notes/CreateEditNoteViewModel.kt +++ b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/notes/CreateEditNoteViewModel.kt @@ -21,6 +21,7 @@ import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -111,8 +112,8 @@ class CreateEditNoteViewModel(application: Application) : AndroidViewModel(appli return id } - fun update(note: Note) { - viewModelScope.launch(Dispatchers.Default) { + fun update(note: Note): Job { + return viewModelScope.launch(Dispatchers.Default) { database.noteDao().update(note) } } diff --git a/gradlew b/gradlew old mode 100644 new mode 100755