diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 5ce8c09e..91b9a68b 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -15,6 +15,12 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4.1.1 + - uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + check-latest: true + cache: 'gradle' - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@v1 @@ -24,8 +30,14 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4.1.1 + - uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + check-latest: true + cache: 'gradle' - name: Lint - run: bash ./gradlew lintDevDebug --stacktrace + run: bash ./gradlew lintDevDebug --stacktrace --no-configuration-cache test: name: Unit tests @@ -33,8 +45,14 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4.1.1 + - uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + check-latest: true + cache: 'gradle' - name: Unit tests - run: bash ./gradlew test --stacktrace + run: bash ./gradlew test --stacktrace --no-configuration-cache apk: name: Generate APK @@ -42,8 +60,14 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4.1.1 + - uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + check-latest: true + cache: 'gradle' - name: Build debug APK - run: bash ./gradlew assembleDev --stacktrace + run: bash ./gradlew assembleDev --stacktrace --no-configuration-cache - name: Upload APK uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 1c3fa463..25e8ecd8 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -38,12 +38,12 @@ jobs: - name: Set up JDK 17 uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0 with: - distribution: "temurin" - java-version: 17 + distribution: 'temurin' + java-version: '17' - name: Assemble run: | mkdir -p "$HOME/.gradle" echo "org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError" > "$HOME/.gradle/gradle.properties" - ./gradlew assembleDebug + ./gradlew assembleDebug --no-configuration-cache - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@b374143c1149a9115d881581d29b8390bbcbb59c # v3.22.11 diff --git a/app/build.gradle b/app/build.gradle index beb52cdf..5cfa0091 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,18 +2,13 @@ apply plugin: 'com.android.application' apply plugin: 'org.jetbrains.kotlin.android' android { - compileSdkVersion 33 - - compileOptions { - coreLibraryDesugaringEnabled true - sourceCompatibility JavaVersion.VERSION_11 - targetCompatibility JavaVersion.VERSION_11 - } + compileSdk 34 + namespace 'it.niedermann.owncloud.notes' defaultConfig { applicationId "it.niedermann.owncloud.notes" - minSdkVersion 24 - targetSdkVersion 33 + minSdk 24 + targetSdk 34 versionCode 40020000 versionName "4.2.0 Alpha1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -24,8 +19,19 @@ android { } } + compileOptions { + coreLibraryDesugaringEnabled true + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + + kotlinOptions { + jvmTarget = '17' + } + buildFeatures { viewBinding true + buildConfig true } buildTypes { @@ -60,25 +66,25 @@ android { includeAndroidResources true } } - lint { + + lintOptions { abortOnError false disable 'MissingTranslation' } - namespace 'it.niedermann.owncloud.notes' } ext { glideVersion = '4.16.0' - roomVersion = "2.5.1" + roomVersion = "2.6.1" } dependencies { - coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3' + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' // Nextcloud SSO - implementation 'com.github.nextcloud.android-common:ui:0.12.0' - implementation 'com.github.nextcloud:Android-SingleSignOn:0.8.1' - implementation 'com.github.stefan-niedermann:android-commons:0.2.9' + implementation 'com.github.nextcloud.android-common:ui:0.13.0' + implementation 'com.github.nextcloud:Android-SingleSignOn:1.0.0' + implementation 'com.github.stefan-niedermann:android-commons:0.4.0' implementation "com.github.stefan-niedermann.nextcloud-commons:sso-glide:$commonsVersion" implementation "com.github.stefan-niedermann.nextcloud-commons:exception:$commonsVersion" implementation("com.github.stefan-niedermann.nextcloud-commons:markdown:$commonsVersion") { @@ -91,16 +97,16 @@ dependencies { // Android X implementation 'androidx.appcompat:appcompat:1.6.1' - implementation 'androidx.core:core-ktx:1.10.1' + implementation 'androidx.core:core-ktx:1.12.0' implementation 'androidx.core:core-splashscreen:1.0.1' - implementation 'androidx.fragment:fragment:1.6.1' - implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2' + implementation 'androidx.fragment:fragment:1.6.2' + implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0' implementation 'androidx.preference:preference:1.2.1' implementation 'androidx.recyclerview:recyclerview-selection:1.1.0' implementation 'androidx.recyclerview:recyclerview:1.3.2' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' - implementation 'androidx.work:work-runtime:2.8.1' - implementation 'com.google.android.material:material:1.9.0' + implementation 'androidx.work:work-runtime:2.9.0' + implementation 'com.google.android.material:material:1.11.0' // Database implementation "androidx.room:room-runtime:${roomVersion}" diff --git a/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedActivity.java index 113db2a9..a3f55c24 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedActivity.java @@ -20,7 +20,7 @@ public abstract class BrandedActivity extends AppCompatActivity implements Brand super.onStart(); final var typedValue = new TypedValue(); - getTheme().resolveAttribute(R.attr.colorAccent, typedValue, true); + getTheme().resolveAttribute(com.google.android.material.R.attr.colorAccent, typedValue, true); colorAccent = typedValue.data; readBrandMainColorLiveData(this).observe(this, this::applyBrand); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedFragment.java b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedFragment.java index ac197ef8..bed27575 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedFragment.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedFragment.java @@ -23,9 +23,9 @@ public abstract class BrandedFragment extends Fragment implements Branded { final var context = requireContext(); final var typedValue = new TypedValue(); - context.getTheme().resolveAttribute(R.attr.colorAccent, typedValue, true); + context.getTheme().resolveAttribute(com.google.android.material.R.attr.colorAccent, typedValue, true); colorAccent = typedValue.data; - context.getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true); + context.getTheme().resolveAttribute(com.google.android.material.R.attr.colorPrimary, typedValue, true); colorPrimary = typedValue.data; @ColorInt final int color = BrandingUtil.readBrandMainColor(context); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/edit/BaseNoteFragment.java b/app/src/main/java/it/niedermann/owncloud/notes/edit/BaseNoteFragment.java index 16245433..1d6adc0e 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/edit/BaseNoteFragment.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/edit/BaseNoteFragment.java @@ -103,7 +103,7 @@ public abstract class BaseNoteFragment extends BrandedFragment implements Catego if (accountId > 0) { /* Switch account if account id has been provided */ this.localAccount = repo.getAccountById(accountId); - SingleAccountHelper.setCurrentAccount(requireContext().getApplicationContext(), localAccount.getAccountName()); + SingleAccountHelper.commitCurrentAccount(requireContext().getApplicationContext(), localAccount.getAccountName()); } isNew = false; note = originalNote = repo.getNoteById(id); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/edit/EditNoteActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/edit/EditNoteActivity.java index 71b43db5..2b49cc29 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/edit/EditNoteActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/edit/EditNoteActivity.java @@ -71,7 +71,7 @@ public class EditNoteActivity extends LockedActivity implements BaseNoteFragment try { if (SingleAccountHelper.getCurrentSingleSignOnAccount(this) == null) { - throw new NoCurrentAccountSelectedException(); + throw new NoCurrentAccountSelectedException(this); } } catch (NextcloudFilesAppAccountNotFoundException | NoCurrentAccountSelectedException e) { Toast.makeText(this, R.string.no_account_configured_yet, Toast.LENGTH_LONG).show(); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/edit/SearchableBaseNoteFragment.java b/app/src/main/java/it/niedermann/owncloud/notes/edit/SearchableBaseNoteFragment.java index 10c9510c..1ca1c5f5 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/edit/SearchableBaseNoteFragment.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/edit/SearchableBaseNoteFragment.java @@ -117,8 +117,7 @@ public abstract class SearchableBaseNoteFragment extends BaseNoteFragment { searchMenuItem.collapseActionView(); - final var searchEditFrame = searchView.findViewById(R.id - .search_edit_frame); + final var searchEditFrame = searchView.findViewById(androidx.appcompat.R.id.search_edit_frame); searchEditFrame.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { int oldVisibility = -1; diff --git a/app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportAccountActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportAccountActivity.java index 72ec0c26..c4e58079 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportAccountActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportAccountActivity.java @@ -88,7 +88,7 @@ public class ImportAccountActivity extends AppCompatActivity { AccountImporter.onActivityResult(requestCode, resultCode, data, ImportAccountActivity.this, ssoAccount -> { runOnUiThread(() -> binding.progressCircular.setVisibility(View.VISIBLE)); - SingleAccountHelper.setCurrentAccount(getApplicationContext(), ssoAccount.name); + SingleAccountHelper.commitCurrentAccount(getApplicationContext(), ssoAccount.name); executor.submit(() -> { Log.i(TAG, "Added account: " + "name:" + ssoAccount.name + ", " + ssoAccount.url + ", userId" + ssoAccount.userId); try { @@ -135,7 +135,7 @@ public class ImportAccountActivity extends AppCompatActivity { } catch (Throwable t) { t.printStackTrace(); ApiProvider.getInstance().invalidateAPICache(ssoAccount); - SingleAccountHelper.setCurrentAccount(this, null); + SingleAccountHelper.commitCurrentAccount(this, null); runOnUiThread(() -> { restoreCleanState(); if (t instanceof NextcloudHttpRequestFailedException && ((NextcloudHttpRequestFailedException) t).getStatusCode() == HttpURLConnection.HTTP_UNAVAILABLE) { diff --git a/app/src/main/java/it/niedermann/owncloud/notes/main/MainViewModel.java b/app/src/main/java/it/niedermann/owncloud/notes/main/MainViewModel.java index 75d02c52..ec725444 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/main/MainViewModel.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/main/MainViewModel.java @@ -121,7 +121,7 @@ public class MainViewModel extends AndroidViewModel { public void postCurrentAccount(@NonNull Account account) { state.set(KEY_CURRENT_ACCOUNT, account); BrandingUtil.saveBrandColor(getApplication(), account.getColor()); - SingleAccountHelper.setCurrentAccount(getApplication(), account.getAccountName()); + SingleAccountHelper.commitCurrentAccount(getApplication(), account.getAccountName()); final var currentAccount = this.currentAccount.getValue(); // If only ETag or colors change, we must not reset the navigation diff --git a/app/src/main/java/it/niedermann/owncloud/notes/main/MultiSelectedActionModeCallback.java b/app/src/main/java/it/niedermann/owncloud/notes/main/MultiSelectedActionModeCallback.java index 194dcbc8..6caf4f22 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/main/MultiSelectedActionModeCallback.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/main/MultiSelectedActionModeCallback.java @@ -72,7 +72,7 @@ public class MultiSelectedActionModeCallback implements Callback { this.fragmentManager = fragmentManager; final TypedValue typedValue = new TypedValue(); - context.getTheme().resolveAttribute(R.attr.colorAccent, typedValue, true); + context.getTheme().resolveAttribute(com.google.android.material.R.attr.colorAccent, typedValue, true); colorAccent = typedValue.data; } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountsViewModel.java b/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountsViewModel.java index b625b076..6cbc199d 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountsViewModel.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountsViewModel.java @@ -66,7 +66,7 @@ public class ManageAccountsViewModel extends AndroidViewModel { } public void selectAccount(@Nullable Account account, @NonNull Context context) { - SingleAccountHelper.setCurrentAccount(context, (account == null) ? null : account.getAccountName()); + SingleAccountHelper.commitCurrentAccount(context, (account == null) ? null : account.getAccountName()); } public void countUnsynchronizedNotes(long accountId, @NonNull IResponseCallback callback) { diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/ApiProvider.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/ApiProvider.java index 4be0a493..bd1ae4eb 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/ApiProvider.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/ApiProvider.java @@ -124,7 +124,7 @@ public class ApiProvider { if (API_CACHE.containsKey(ssoAccount.name)) { final var nextcloudAPI = API_CACHE.get(ssoAccount.name); if (nextcloudAPI != null) { - nextcloudAPI.stop(); + nextcloudAPI.close(); } API_CACHE.remove(ssoAccount.name); } @@ -141,7 +141,7 @@ public class ApiProvider { if (API_CACHE.containsKey(key)) { final var nextcloudAPI = API_CACHE.get(key); if (nextcloudAPI != null) { - nextcloudAPI.stop(); + nextcloudAPI.close(); } API_CACHE.remove(key); } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesRepository.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesRepository.java index 1ea2f7cb..74589cbc 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesRepository.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesRepository.java @@ -187,7 +187,7 @@ public class NotesRepository { public void onError(@NonNull Throwable t) { Log.e(TAG, "… Error while importing " + account.getAccountName() + ": " + t.getMessage()); deleteAccount(account); - SingleAccountHelper.setCurrentAccount(context, null); + SingleAccountHelper.commitCurrentAccount(context, null); callback.onError(t); } }); @@ -195,7 +195,7 @@ public class NotesRepository { Log.e(TAG, "… Could not find " + SingleSignOnAccount.class.getSimpleName() + " for account name " + account.getAccountName()); importExecutor.submit(() -> { deleteAccount(account); - SingleAccountHelper.setCurrentAccount(context, null); + SingleAccountHelper.commitCurrentAccount(context, null); callback.onError(e); }); } @@ -203,7 +203,7 @@ public class NotesRepository { Log.e(TAG, "… No network connection available to import " + account.getAccountName()); importExecutor.submit(() -> { deleteAccount(account); - SingleAccountHelper.setCurrentAccount(context, null); + SingleAccountHelper.commitCurrentAccount(context, null); callback.onError(new NetworkErrorException()); }); } diff --git a/build.gradle b/build.gradle index 2d4c67a2..ef8ab2c5 100644 --- a/build.gradle +++ b/build.gradle @@ -1,16 +1,18 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { ext { - kotlinVersion = '1.8.22' - commonsVersion = '1.8.2' + kotlinVersion = '1.9.22' + commonsVersion = '1.9.0' } repositories { mavenCentral() google() } dependencies { - classpath 'com.android.tools.build:gradle:7.4.2' + classpath 'com.android.tools.build:gradle:8.2.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" // NOTE: Do not place your application dependencies here; they belong @@ -28,12 +30,7 @@ allprojects { } subprojects { - tasks.withType(Test) { + tasks.withType(Test).configureEach { maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1 } - tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) { - kotlinOptions { - jvmTarget = "11" - } - } } diff --git a/gradle.properties b/gradle.properties index 0d0f8dee..4e8e44e9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,20 +1,3 @@ -# Project-wide Gradle settings. - -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. - -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html - -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8 +org.gradle.configuration-cache=true android.useAndroidX=true -org.gradle.jvmargs=-Xmx4096m -# Default value: -Xmx10248m -XX:MaxPermSize=256m -# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 - -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ae04661e..15de9024 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists