diff --git a/.github/workflows/android-test.yml b/.github/workflows/android-test.yml new file mode 100644 index 0000000..efd1db7 --- /dev/null +++ b/.github/workflows/android-test.yml @@ -0,0 +1,98 @@ +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 BackupApp/src/androidTest)" ] && echo 'true' || echo 'false')" + echo "NOT_EMPTY=$([ "$(ls -A BackupApp/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 BackupApp/build.gradle | grep minSdkVersion | rev | cut -d' ' -f 1 | rev)" >> $GITHUB_OUTPUT + echo "TARGET_SDK_VERSION=$(cat BackupApp/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 BackupApp/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 + ./gradlew :BackupApp: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/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9e60fe6 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,49 @@ +name: Continuous Integration +on: [push, pull_request] + +jobs: + test: + 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 + + build: + 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: Build the app + run: bash ./gradlew build --stacktrace diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index b85bc32..0000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Continuous integration - -on: [push, pull_request] - -jobs: - test: - name: Unit Tests - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - with: - submodules: 'recursive' - - name: Make gradlew executable - run: chmod +x ./gradlew - - name: Run unit tests - run: ./gradlew test - - name: Android Test Report - uses: asadmansr/android-test-report-action@v1.2.0 - -#### These tests can not run because the api and another app needs to be installed -# 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 - runs-on: ubuntu-20.04 - - steps: - - uses: actions/checkout@v2 - with: - submodules: 'recursive' - - name: Make gradlew executable - run: chmod +x ./gradlew - - name: Build debug APK - run: ./gradlew assembleDebug diff --git a/.gitignore b/.gitignore index 1f4cbd7..aa9c63f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,8 @@ *.iml .gradle /local.properties -/.idea/caches -/.idea/libraries -/.idea/modules.xml -/.idea/workspace.xml -/.idea/navEditor.xml -/.idea/assetWizardSettings.xml +.idea/ +misc.xml .DS_Store /build /captures diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml deleted file mode 100644 index 88ea3aa..0000000 --- a/.idea/codeStyles/Project.xml +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - - - - -
- - - - xmlns:android - - ^$ - - - -
-
- - - - xmlns:.* - - ^$ - - - BY_NAME - -
-
- - - - .*:id - - http://schemas.android.com/apk/res/android - - - -
-
- - - - .*:name - - http://schemas.android.com/apk/res/android - - - -
-
- - - - name - - ^$ - - - -
-
- - - - style - - ^$ - - - -
-
- - - - .* - - ^$ - - - BY_NAME - -
-
- - - - .* - - http://schemas.android.com/apk/res/android - - - ANDROID_ATTRIBUTE_ORDER - -
-
- - - - .* - - .* - - - BY_NAME - -
-
-
-
- - -
-
\ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100644 index 79ee123..0000000 --- a/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index fb7f4a8..0000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml deleted file mode 100644 index c81a0e2..0000000 --- a/.idea/gradle.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml deleted file mode 100644 index a5f05cd..0000000 --- a/.idea/jarRepositories.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 9815e2a..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 407beea..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/BackupAPI b/BackupAPI index de5ed1f..8687a8d 160000 --- a/BackupAPI +++ b/BackupAPI @@ -1 +1 @@ -Subproject commit de5ed1fadd0b5320dab3f6f0ecfc569cfcde87c5 +Subproject commit 8687a8dbd170866707dc41bcb879375400ef697a diff --git a/BackupApp/build.gradle b/BackupApp/build.gradle index de50e41..e10153a 100644 --- a/BackupApp/build.gradle +++ b/BackupApp/build.gradle @@ -1,8 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-parcelize' apply plugin: 'kotlin-kapt' - def pfaFile = rootProject.file('pfa.properties') android { @@ -19,14 +18,14 @@ android { } } } - compileSdkVersion 32 + compileSdk 34 defaultConfig { applicationId "org.secuso.privacyfriendlybackup" minSdkVersion 21 - targetSdkVersion 32 - versionCode 4 - versionName "1.3" + targetSdkVersion 34 + versionCode 5 + versionName "1.3.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -41,12 +40,17 @@ android { } } - applicationVariants.all { variant -> + android.applicationVariants.configureEach { variant -> variant.outputs.all { - outputFileName = "pfa-backup-${variant.name}-v${variant.versionName}.apk" + def appName = "pfa-backup" + outputFileName = appName + "-${variant.name}-v${variant.versionName}.apk" } } + buildFeatures { + viewBinding true + } + buildTypes { release { minifyEnabled false @@ -61,13 +65,17 @@ android { } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8.toString() + jvmTarget = JavaVersion.VERSION_17.toString() + } + + kotlin { + jvmToolchain(17) } sourceSets { @@ -76,57 +84,60 @@ android { lint { abortOnError false } + namespace 'org.secuso.privacyfriendlybackup' } dependencies { implementation project(path: ':BackupAPI') - implementation project(path: ':jsonviewer') implementation fileTree(dir: "libs", include: ["*.jar"]) implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3' - implementation 'androidx.core:core-ktx:1.8.0' - implementation 'androidx.appcompat:appcompat:1.4.2' + implementation 'androidx.core:core-ktx:1.13.1' + implementation 'androidx.appcompat:appcompat:1.7.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0' - implementation 'androidx.recyclerview:recyclerview:1.2.1' - implementation 'com.google.android.material:material:1.6.1' + implementation 'androidx.recyclerview:recyclerview:1.3.2' + implementation 'com.google.android.material:material:1.12.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - testImplementation 'junit:junit:4.13.1' - androidTestImplementation 'androidx.test.ext:junit:1.1.3' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.2.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' // OpenPGP API implementation 'org.sufficientlysecure:openpgp-api:12.0' // WorkManager - def work_version = "2.7.1" + def work_version = "2.9.0" implementation "androidx.work:work-runtime:$work_version" implementation "androidx.work:work-runtime-ktx:$work_version" androidTestImplementation "androidx.work:work-testing:$work_version" testImplementation "androidx.work:work-testing:$work_version" // Room Database - def roomVersion = "2.4.2" + def roomVersion = "2.6.1" implementation "androidx.room:room-runtime:$roomVersion" annotationProcessor "androidx.room:room-compiler:$roomVersion" kapt "androidx.room:room-compiler:$roomVersion" implementation "androidx.room:room-ktx:$roomVersion" // Lifecycle - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0" - implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.0' + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.3" + implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.8.3' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' - implementation 'androidx.lifecycle:lifecycle-common-java8:2.5.0' + implementation 'androidx.lifecycle:lifecycle-common-java8:2.8.3' // Preferences - def preference_version = "1.2.0" + def preference_version = "1.2.1" implementation "androidx.preference:preference-ktx:$preference_version" // Glide implementation 'com.github.bumptech.glide:glide:4.11.0' + // JSON Viewer + implementation 'com.yuyh.json:jsonviewer:1.0.6' + // Retrofit for Google Drive Test implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' diff --git a/BackupApp/src/main/AndroidManifest.xml b/BackupApp/src/main/AndroidManifest.xml index 3b89191..9900b86 100644 --- a/BackupApp/src/main/AndroidManifest.xml +++ b/BackupApp/src/main/AndroidManifest.xml @@ -1,7 +1,6 @@ + xmlns:tools="http://schemas.android.com/tools"> @@ -12,6 +11,8 @@ + + diff --git a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/BackupApplication.kt b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/BackupApplication.kt index 606c463..b86df29 100644 --- a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/BackupApplication.kt +++ b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/BackupApplication.kt @@ -5,8 +5,12 @@ import android.app.NotificationChannel import android.app.NotificationManager import android.os.Build import android.util.Log -import androidx.work.* -import org.secuso.privacyfriendlybackup.data.room.BackupDatabase +import androidx.work.BackoffPolicy +import androidx.work.Configuration +import androidx.work.ExistingPeriodicWorkPolicy +import androidx.work.PeriodicWorkRequestBuilder +import androidx.work.WorkManager +import androidx.work.WorkRequest import org.secuso.privacyfriendlybackup.worker.BackupJobManagerWorker import java.util.concurrent.TimeUnit @@ -29,7 +33,7 @@ class BackupApplication : Application(), Configuration.Provider { Log.d(TAG, "schedulePeriodicWork()") val periodicJobManagerWork = PeriodicWorkRequestBuilder(15, TimeUnit.MINUTES) - .setBackoffCriteria(BackoffPolicy.LINEAR, PeriodicWorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS) + .setBackoffCriteria(BackoffPolicy.LINEAR, WorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS) .build() WorkManager.getInstance(this).enqueueUniquePeriodicWork( @@ -54,8 +58,8 @@ class BackupApplication : Application(), Configuration.Provider { } } - override fun getWorkManagerConfiguration(): Configuration = - Configuration.Builder() + override val workManagerConfiguration: Configuration + get() = Configuration.Builder() .setMinimumLoggingLevel(Log.ERROR) .build() } \ No newline at end of file diff --git a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/data/room/model/BackupJob.kt b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/data/room/model/BackupJob.kt index 4db60ef..a7d6d0d 100644 --- a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/data/room/model/BackupJob.kt +++ b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/data/room/model/BackupJob.kt @@ -3,8 +3,7 @@ package org.secuso.privacyfriendlybackup.data.room.model import android.os.Parcelable import androidx.recyclerview.widget.DiffUtil import androidx.room.* -import androidx.room.ForeignKey.CASCADE -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize import org.secuso.privacyfriendlybackup.data.BackupJobManager import org.secuso.privacyfriendlybackup.data.room.model.enums.BackupJobAction import java.util.* diff --git a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/data/room/model/InternalBackupData.kt b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/data/room/model/InternalBackupData.kt index 068daa9..6f86048 100644 --- a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/data/room/model/InternalBackupData.kt +++ b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/data/room/model/InternalBackupData.kt @@ -4,7 +4,7 @@ import android.os.Parcelable import androidx.room.Entity import androidx.room.Index import androidx.room.PrimaryKey -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize import java.util.* @Parcelize diff --git a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/data/room/model/PFAJob.kt b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/data/room/model/PFAJob.kt index 7a5a52b..9ad24c3 100644 --- a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/data/room/model/PFAJob.kt +++ b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/data/room/model/PFAJob.kt @@ -2,7 +2,7 @@ package org.secuso.privacyfriendlybackup.data.room.model import android.os.Parcelable import androidx.room.* -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize import org.secuso.privacyfriendlybackup.data.room.model.enums.PFAJobAction import java.util.* diff --git a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/data/room/model/StoredBackupMetaData.kt b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/data/room/model/StoredBackupMetaData.kt index a3a99df..35b2e6f 100644 --- a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/data/room/model/StoredBackupMetaData.kt +++ b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/data/room/model/StoredBackupMetaData.kt @@ -4,7 +4,7 @@ import android.os.Parcelable import androidx.room.Entity import androidx.room.Index import androidx.room.PrimaryKey -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize import org.secuso.privacyfriendlybackup.data.room.model.enums.StorageType import java.util.* diff --git a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/application/ApplicationOverviewFragment.kt b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/application/ApplicationOverviewFragment.kt index e6fd89b..01297da 100644 --- a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/application/ApplicationOverviewFragment.kt +++ b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/application/ApplicationOverviewFragment.kt @@ -8,10 +8,10 @@ import android.view.* import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.observe import androidx.recyclerview.widget.LinearLayoutManager -import kotlinx.android.synthetic.main.fragment_backup_overview.* import org.secuso.privacyfriendlybackup.BackupApplication import org.secuso.privacyfriendlybackup.R import org.secuso.privacyfriendlybackup.data.room.model.BackupJob +import org.secuso.privacyfriendlybackup.databinding.FragmentBackupOverviewBinding import org.secuso.privacyfriendlybackup.ui.common.BaseFragment import org.secuso.privacyfriendlybackup.ui.common.DisplayMenuItemActivity import org.secuso.privacyfriendlybackup.ui.main.MainActivity @@ -27,6 +27,7 @@ class ApplicationOverviewFragment : BaseFragment(), ApplicationAdapter.ManageLis private lateinit var adapter : ApplicationAdapter private var oldMode : Mode = Mode.NORMAL + lateinit var binding: FragmentBackupOverviewBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -42,7 +43,8 @@ class ApplicationOverviewFragment : BaseFragment(), ApplicationAdapter.ManageLis } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_backup_overview, container, false) + binding = FragmentBackupOverviewBinding.inflate(layoutInflater) + return binding.root } override fun onActivityCreated(savedInstanceState: Bundle?) { @@ -53,11 +55,11 @@ class ApplicationOverviewFragment : BaseFragment(), ApplicationAdapter.ManageLis viewModel = ViewModelProvider(this)[ApplicationOverviewViewModel::class.java] adapter = ApplicationAdapter(requireContext(), this, viewLifecycleOwner) - fragment_backup_overview_list.adapter = adapter - fragment_backup_overview_list.layoutManager = + binding.fragmentBackupOverviewList.adapter = adapter + binding.fragmentBackupOverviewList.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) - backup_overview_no_entries_name.setText(R.string.application_overview_no_entries_text) + binding.backupOverviewNoEntriesName.setText(R.string.application_overview_no_entries_text) viewModel.appLiveData.observe(viewLifecycleOwner) { data -> adapter.setData(data) @@ -119,6 +121,6 @@ class ApplicationOverviewFragment : BaseFragment(), ApplicationAdapter.ManageLis } private fun displayNoElementsImage(show: Boolean) { - backup_overview_no_entries.visibility = if(show) View.VISIBLE else View.GONE + binding.backupOverviewNoEntries.visibility = if(show) View.VISIBLE else View.GONE } } \ No newline at end of file diff --git a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/backup/BackupOverviewFragment.kt b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/backup/BackupOverviewFragment.kt index c8f5ea2..107fc63 100644 --- a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/backup/BackupOverviewFragment.kt +++ b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/backup/BackupOverviewFragment.kt @@ -19,13 +19,13 @@ import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearSmoothScroller import androidx.recyclerview.widget.RecyclerView.SmoothScroller -import kotlinx.android.synthetic.main.fragment_backup_overview.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.secuso.privacyfriendlybackup.R import org.secuso.privacyfriendlybackup.data.BackupDataStorageRepository +import org.secuso.privacyfriendlybackup.databinding.FragmentBackupOverviewBinding import org.secuso.privacyfriendlybackup.preference.PreferenceKeys.DIALOG_SKIP_IMPORT_START import org.secuso.privacyfriendlybackup.ui.common.BaseFragment import org.secuso.privacyfriendlybackup.ui.common.DisplayMenuItemActivity @@ -51,6 +51,7 @@ class BackupOverviewFragment : BaseFragment(), private lateinit var viewModel: BackupOverviewViewModel private lateinit var adapter : FilterableBackupAdapter + private lateinit var binding: FragmentBackupOverviewBinding private var toolbarDeleteIcon: MenuItem? = null private var searchIcon: MenuItem? = null @@ -83,7 +84,8 @@ class BackupOverviewFragment : BaseFragment(), container: ViewGroup?, savedInstanceState: Bundle? ): View? { - return inflater.inflate(R.layout.fragment_backup_overview, container, false) + binding = FragmentBackupOverviewBinding.inflate(inflater, container, false) + return binding.root } override fun onActivityCreated(savedInstanceState: Bundle?) { @@ -98,8 +100,8 @@ class BackupOverviewFragment : BaseFragment(), this ) - fragment_backup_overview_list.adapter = adapter - fragment_backup_overview_list.layoutManager = when { + binding.fragmentBackupOverviewList.adapter = adapter + binding.fragmentBackupOverviewList.layoutManager = when { isXLargeTablet() -> { GridLayoutManager( context, @@ -121,7 +123,7 @@ class BackupOverviewFragment : BaseFragment(), } } - fab.setOnClickListener { + binding.fab.setOnClickListener { if(Mode.DELETE.isActiveIn(viewModel.getCurrentMode())) { val builder = AlertDialog.Builder(requireContext()).apply { @@ -204,7 +206,7 @@ class BackupOverviewFragment : BaseFragment(), } private fun displayNoElementsImage(show: Boolean) { - backup_overview_no_entries.visibility = if(show) View.VISIBLE else View.GONE + binding.backupOverviewNoEntries.visibility = if(show) View.VISIBLE else View.GONE } private fun playAnimationIfApplicable(data: List) { @@ -222,7 +224,7 @@ class BackupOverviewFragment : BaseFragment(), delay(250L) Log.d(TAG, "## finding viewholder for item id $highlight") - val vh = fragment_backup_overview_list.findViewHolderForItemId(highlight) + val vh = binding.fragmentBackupOverviewList.findViewHolderForItemId(highlight) if(vh != null) { (vh as FilterableBackupAdapter.ViewHolder).apply { ObjectAnimator.ofObject( @@ -254,7 +256,7 @@ class BackupOverviewFragment : BaseFragment(), } } smoothScroller.targetPosition = position - fragment_backup_overview_list.layoutManager?.startSmoothScroll(smoothScroller) + binding.fragmentBackupOverviewList.layoutManager?.startSmoothScroll(smoothScroller) } override fun onBackPressed() { @@ -425,7 +427,7 @@ class BackupOverviewFragment : BaseFragment(), toolbarDeleteIcon?.isVisible = false selectAllIcon?.isVisible = true - fab.show() + binding.fab.show() } override fun onItemClick( @@ -486,7 +488,7 @@ class BackupOverviewFragment : BaseFragment(), toolbarDeleteIcon?.isVisible = true selectAllIcon?.isVisible = false - fab?.hide() + binding.fab.hide() adapter.disableDeleteMode() } diff --git a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/common/DisplayMenuItemActivity.kt b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/common/DisplayMenuItemActivity.kt index c035fc8..5f609a4 100644 --- a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/common/DisplayMenuItemActivity.kt +++ b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/common/DisplayMenuItemActivity.kt @@ -6,8 +6,8 @@ import android.util.Log import android.view.MenuItem import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment -import kotlinx.android.synthetic.main.activity_display_menu_item.* import org.secuso.privacyfriendlybackup.R +import org.secuso.privacyfriendlybackup.databinding.ActivityDisplayMenuItemBinding import org.secuso.privacyfriendlybackup.ui.main.MainActivity /** @@ -18,10 +18,13 @@ import org.secuso.privacyfriendlybackup.ui.main.MainActivity */ class DisplayMenuItemActivity : AppCompatActivity() { + lateinit var binding: ActivityDisplayMenuItemBinding + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_display_menu_item) - setSupportActionBar(toolbar) + binding = ActivityDisplayMenuItemBinding.inflate(layoutInflater) + setContentView(binding.root) + setSupportActionBar(binding.toolbar) supportActionBar?.setDisplayHomeAsUpEnabled(true) diff --git a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/encryption/EncryptionSettingsActivity.kt b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/encryption/EncryptionSettingsActivity.kt index 3946f12..00377d2 100644 --- a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/encryption/EncryptionSettingsActivity.kt +++ b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/encryption/EncryptionSettingsActivity.kt @@ -2,14 +2,16 @@ package org.secuso.privacyfriendlybackup.ui.encryption import android.os.Bundle import androidx.appcompat.app.AppCompatActivity -import kotlinx.android.synthetic.main.activity_display_menu_item.* import org.secuso.privacyfriendlybackup.R +import org.secuso.privacyfriendlybackup.databinding.ActivityDisplayMenuItemBinding import org.secuso.privacyfriendlybackup.ui.backup.BackupOverviewFragment class EncryptionSettingsActivity : AppCompatActivity(){ + lateinit var binding: ActivityDisplayMenuItemBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_display_menu_item) + binding = ActivityDisplayMenuItemBinding.inflate(layoutInflater) + setContentView(binding.root) initResources() @@ -24,7 +26,7 @@ class EncryptionSettingsActivity : AppCompatActivity(){ } private fun initResources() { - setSupportActionBar(toolbar) + setSupportActionBar(binding.toolbar) supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setTitle(R.string.app_name) } diff --git a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/help/HelpFragment.kt b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/help/HelpFragment.kt index 4a71244..e1ddde5 100644 --- a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/help/HelpFragment.kt +++ b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/help/HelpFragment.kt @@ -4,18 +4,19 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import kotlinx.android.synthetic.main.fragment_help.* -import org.secuso.privacyfriendlybackup.R +import org.secuso.privacyfriendlybackup.databinding.FragmentHelpBinding import org.secuso.privacyfriendlybackup.ui.common.BaseFragment class HelpFragment : BaseFragment() { + lateinit var binding: FragmentHelpBinding override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { - return inflater.inflate(R.layout.fragment_help, container, false) + binding = FragmentHelpBinding.inflate(layoutInflater) + return binding.root } override fun onActivityCreated(savedInstanceState: Bundle?) { @@ -27,7 +28,7 @@ class HelpFragment : BaseFragment() { val expandableListDetail = helpDataDump.dataGeneral val expandableListTitleGeneral: List = ArrayList(expandableListDetail.keys) expandableListAdapter = ExpandableListAdapter(requireActivity(), expandableListTitleGeneral, expandableListDetail) - generalExpandableListView.setAdapter(expandableListAdapter) + binding.generalExpandableListView.setAdapter(expandableListAdapter) } override fun onBackPressed() { diff --git a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/inspection/DataInspectionFragment.kt b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/inspection/DataInspectionFragment.kt index 500c34a..24e5192 100644 --- a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/inspection/DataInspectionFragment.kt +++ b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/inspection/DataInspectionFragment.kt @@ -23,10 +23,10 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.ViewModelProvider import androidx.preference.PreferenceManager import com.bumptech.glide.Glide -import kotlinx.android.synthetic.main.data_inspection_fragment.* -import kotlinx.android.synthetic.main.item_application_job.* import org.openintents.openpgp.OpenPgpSignatureResult import org.secuso.privacyfriendlybackup.R +import org.secuso.privacyfriendlybackup.databinding.DataInspectionFragmentBinding +import org.secuso.privacyfriendlybackup.databinding.ItemApplicationJobBinding import org.secuso.privacyfriendlybackup.preference.PreferenceKeys import org.secuso.privacyfriendlybackup.ui.backup.BackupOverviewFragment import java.io.FileNotFoundException @@ -41,6 +41,8 @@ class DataInspectionFragment : Fragment() { private var encryptionEnabled : Boolean = false private var showSigInfo: Boolean = false + lateinit var dataBinding: DataInspectionFragmentBinding + companion object { fun newInstance() = DataInspectionFragment() @@ -58,7 +60,8 @@ class DataInspectionFragment : Fragment() { } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - return inflater.inflate(R.layout.data_inspection_fragment, container, false) + dataBinding = DataInspectionFragmentBinding.inflate(layoutInflater) + return dataBinding.root } override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { @@ -105,9 +108,9 @@ class DataInspectionFragment : Fragment() { showSigInfo = !showSigInfo val set = ConstraintSet() - set.clone(data_inspection) + set.clone(dataBinding.dataInspection) set.setVisibility(R.id.data_inspection_encryption_details, if(showSigInfo) View.VISIBLE else View.GONE) - set.applyTo(data_inspection) + set.applyTo(dataBinding.dataInspection) } private fun handleExportClicked() { @@ -224,27 +227,27 @@ class DataInspectionFragment : Fragment() { viewModel.getLoadStatus().observe(viewLifecycleOwner) { Log.d("TEST", "## Load Status Updated To ${it.name}") - Glide.with(requireActivity()).load(it.imageRes).into(data_inspection_load_status_image) - data_inspection_load_status_name.setText(it.descriptionRes) - data_inspection_load_status_image.setColorFilter(ContextCompat.getColor(requireActivity(), it.colorRes)) + Glide.with(requireActivity()).load(it.imageRes).into(dataBinding.dataInspectionSignatureStatus) + dataBinding.dataInspectionLoadStatusName.setText(it.descriptionRes) + dataBinding.dataInspectionLoadStatusImage.setColorFilter(ContextCompat.getColor(requireActivity(), it.colorRes)) when(it) { LoadStatus.UNKNOWN, null -> { - data_inspection_load_status.visibility = View.GONE + dataBinding.dataInspectionLoadStatus.visibility = View.GONE } LoadStatus.ERROR_INVALID_JSON, LoadStatus.ERROR -> { - data_inspection_load_status.visibility = View.VISIBLE + dataBinding.dataInspectionLoadStatus.visibility = View.VISIBLE } LoadStatus.LOADING -> { - data_inspection_load_status.visibility = View.VISIBLE + dataBinding.dataInspectionLoadStatus.visibility = View.VISIBLE } LoadStatus.DECRYPTING -> { - data_inspection_load_status.visibility = View.VISIBLE + dataBinding.dataInspectionLoadStatus.visibility = View.VISIBLE } LoadStatus.DECRYPTION_ERROR -> { - data_inspection_load_status.visibility = View.VISIBLE + dataBinding.dataInspectionLoadStatus.visibility = View.VISIBLE } LoadStatus.DONE -> { - data_inspection_load_status.visibility = View.GONE + dataBinding.dataInspectionLoadStatus.visibility = View.GONE encryptionEnabled = encryptionEnabled and viewModel.isEncrypted @@ -259,31 +262,31 @@ class DataInspectionFragment : Fragment() { } viewModel.getData().observe(viewLifecycleOwner) { - data_inspection_json_list.bindJson(it) + dataBinding.dataInspectionJsonList.bindJson(it) } // Color - data_inspection_json_list.setKeyColor( + dataBinding.dataInspectionJsonList.setKeyColor( ContextCompat.getColor( activity, R.color.colorPrimary ) ) - data_inspection_json_list.setValueTextColor(ContextCompat.getColor(activity, R.color.green)) - data_inspection_json_list.setValueNumberColor( + dataBinding.dataInspectionJsonList.setValueTextColor(ContextCompat.getColor(activity, R.color.green)) + dataBinding.dataInspectionJsonList.setValueNumberColor( ContextCompat.getColor( activity, R.color.colorAccent ) ) - data_inspection_json_list.setValueUrlColor(ContextCompat.getColor(activity, R.color.red)) - data_inspection_json_list.setValueNullColor( + dataBinding.dataInspectionJsonList.setValueUrlColor(ContextCompat.getColor(activity, R.color.red)) + dataBinding.dataInspectionJsonList.setValueNullColor( ContextCompat.getColor( activity, R.color.orange ) ) - data_inspection_json_list.setBracesColor(ContextCompat.getColor(activity, R.color.black)) + dataBinding.dataInspectionJsonList.setBracesColor(ContextCompat.getColor(activity, R.color.black)) //data_inspection_json_list.setTextSize() viewModel.getDecryptionMetaData().observe(requireActivity()) { @@ -297,8 +300,8 @@ class DataInspectionFragment : Fragment() { OpenPgpSignatureResult.RESULT_NO_SIGNATURE -> { // not signed statusText = requireActivity().getString(R.string.signature_result_no_signature) - data_inspection_signature_user_id.visibility = View.GONE - data_inspection_signature_key_id.visibility = View.GONE + dataBinding.dataInspectionSignatureUserId.visibility = View.GONE + dataBinding.dataInspectionSignatureKeyId.visibility = View.GONE } OpenPgpSignatureResult.RESULT_INVALID_SIGNATURE -> { // invalid signature @@ -337,10 +340,10 @@ class DataInspectionFragment : Fragment() { mutate() setTint(color) } - data_inspection_signature_status.setImageDrawable(statusIcon) - data_inspection_signature_status_text.text = statusText - data_inspection_signature_user_id.text = requireActivity().getString(R.string.data_inspection_signature_user_id, it.signature?.primaryUserId) - data_inspection_signature_key_id.text = requireActivity().getString(R.string.data_inspection_signature_key_id, it.signature?.keyId.toString()) + dataBinding.dataInspectionSignatureStatus.setImageDrawable(statusIcon) + dataBinding.dataInspectionSignatureStatusText.text = statusText + dataBinding.dataInspectionSignatureUserId.text = requireActivity().getString(R.string.data_inspection_signature_user_id, it.signature?.primaryUserId) + dataBinding.dataInspectionSignatureKeyId.text = requireActivity().getString(R.string.data_inspection_signature_key_id, it.signature?.keyId.toString()) } } diff --git a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/main/AboutFragment.kt b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/main/AboutFragment.kt index bd3da4d..edce153 100644 --- a/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/main/AboutFragment.kt +++ b/BackupApp/src/main/java/org/secuso/privacyfriendlybackup/ui/main/AboutFragment.kt @@ -5,27 +5,28 @@ import android.text.method.LinkMovementMethod import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import kotlinx.android.synthetic.main.fragment_about.* import org.secuso.privacyfriendlybackup.BuildConfig import org.secuso.privacyfriendlybackup.R +import org.secuso.privacyfriendlybackup.databinding.FragmentAboutBinding import org.secuso.privacyfriendlybackup.ui.common.BaseFragment class AboutFragment : BaseFragment() { - + lateinit var binding: FragmentAboutBinding override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { - return inflater.inflate(R.layout.fragment_about, container, false) + binding = FragmentAboutBinding.inflate(layoutInflater) + return binding.root } override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) - githubURL.movementMethod = LinkMovementMethod.getInstance() - secusoWebsite.movementMethod = LinkMovementMethod.getInstance() - textFieldVersion.text = requireActivity().getString(R.string.version_number, BuildConfig.VERSION_NAME) + binding.githubURL.movementMethod = LinkMovementMethod.getInstance() + binding.secusoWebsite.movementMethod = LinkMovementMethod.getInstance() + binding.textFieldVersion.text = requireActivity().getString(R.string.version_number, BuildConfig.VERSION_NAME) } diff --git a/BackupApp/src/main/res/layout/item_list.xml b/BackupApp/src/main/res/layout/item_list.xml index ced6d38..6258c15 100644 --- a/BackupApp/src/main/res/layout/item_list.xml +++ b/BackupApp/src/main/res/layout/item_list.xml @@ -1,11 +1,16 @@ - \ No newline at end of file + android:layout_height="match_parent"> + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index ba2839c..7e98f85 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,12 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = "1.6.10" + ext.kotlin_version = "1.9.10" repositories { google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:7.2.1' + classpath 'com.android.tools.build:gradle:8.1.4' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong @@ -14,6 +14,11 @@ buildscript { } } +plugins { + id 'com.google.devtools.ksp' version "$kotlin_version-1.0.13" apply false +} + + allprojects { repositories { google() diff --git a/gradle.properties b/gradle.properties index 4d15d01..fde9fa4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,4 +18,7 @@ android.useAndroidX=true # Automatically convert third-party libraries to use AndroidX android.enableJetifier=true # Kotlin code style for this project: "official" or "obsolete": -kotlin.code.style=official \ No newline at end of file +kotlin.code.style=official +android.defaults.buildfeatures.buildconfig=true +android.nonTransitiveRClass=false +android.nonFinalResIds=false \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 204fb37..510e968 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/libs/jsonviewer/.gitignore b/libs/jsonviewer/.gitignore deleted file mode 100644 index 796b96d..0000000 --- a/libs/jsonviewer/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/libs/jsonviewer/build.gradle b/libs/jsonviewer/build.gradle deleted file mode 100644 index e8a321d..0000000 --- a/libs/jsonviewer/build.gradle +++ /dev/null @@ -1,33 +0,0 @@ -apply plugin: 'com.android.library' - -android { - compileSdkVersion 30 - resourcePrefix "jsonviewer" - - defaultConfig { - minSdkVersion 14 - targetSdkVersion 30 - versionCode 6 - versionName "1.0.6" - } - - buildTypes { - release { - postprocessing { - removeUnusedCode false - removeUnusedResources false - obfuscate false - optimizeCode false - proguardFile 'proguard-rules.pro' - } - } - } - -} - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'androidx.recyclerview:recyclerview:1.1.0' -} diff --git a/libs/jsonviewer/proguard-rules.pro b/libs/jsonviewer/proguard-rules.pro deleted file mode 100644 index f1b4245..0000000 --- a/libs/jsonviewer/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile diff --git a/libs/jsonviewer/src/main/AndroidManifest.xml b/libs/jsonviewer/src/main/AndroidManifest.xml deleted file mode 100644 index 7e0335f..0000000 --- a/libs/jsonviewer/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/libs/jsonviewer/src/main/java/com/yuyh/jsonviewer/library/JsonRecyclerView.java b/libs/jsonviewer/src/main/java/com/yuyh/jsonviewer/library/JsonRecyclerView.java deleted file mode 100644 index 99515d8..0000000 --- a/libs/jsonviewer/src/main/java/com/yuyh/jsonviewer/library/JsonRecyclerView.java +++ /dev/null @@ -1,194 +0,0 @@ -package com.yuyh.jsonviewer.library; - -import android.content.Context; -import android.text.style.ForegroundColorSpan; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; - -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import com.yuyh.jsonviewer.library.adapter.BaseJsonViewerAdapter; -import com.yuyh.jsonviewer.library.adapter.JsonViewerAdapter; -import com.yuyh.jsonviewer.library.view.JsonItemView; - -import org.json.JSONArray; -import org.json.JSONObject; - -/** - * Created by yuyuhang on 2017/11/30. - */ -public class JsonRecyclerView extends RecyclerView { - - private BaseJsonViewerAdapter mAdapter; - - public JsonRecyclerView(Context context) { - this(context, null); - } - - public JsonRecyclerView(Context context, @Nullable AttributeSet attrs) { - this(context, attrs, 0); - } - - public JsonRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - initView(); - } - - private void initView() { - setLayoutManager(new LinearLayoutManager(getContext())); - } - - public void bindJson(String jsonStr) { - mAdapter = null; - mAdapter = new JsonViewerAdapter(jsonStr); - setAdapter(mAdapter); - } - - public void bindJson(JSONArray array) { - mAdapter = null; - mAdapter = new JsonViewerAdapter(array); - setAdapter(mAdapter); - } - - public void bindJson(JSONObject object) { - mAdapter = null; - mAdapter = new JsonViewerAdapter(object); - setAdapter(mAdapter); - } - - public void setKeyColor(int color) { - BaseJsonViewerAdapter.KEY_COLOR = color; - } - - public void setValueTextColor(int color) { - BaseJsonViewerAdapter.TEXT_COLOR = color; - } - - public void setValueNumberColor(int color) { - BaseJsonViewerAdapter.NUMBER_COLOR = color; - } - - public void setValueBooleanColor(int color) { - BaseJsonViewerAdapter.BOOLEAN_COLOR = color; - } - - public void setValueUrlColor(int color) { - BaseJsonViewerAdapter.URL_COLOR = color; - } - - public void setValueNullColor(int color) { - BaseJsonViewerAdapter.NUMBER_COLOR = color; - } - - public void setBracesColor(int color) { - BaseJsonViewerAdapter.BRACES_COLOR = color; - } - - public void setTextSize(float sizeDP) { - if (sizeDP < 10) { - sizeDP = 10; - } else if (sizeDP > 30) { - sizeDP = 30; - } - - if (BaseJsonViewerAdapter.TEXT_SIZE_DP != sizeDP) { - BaseJsonViewerAdapter.TEXT_SIZE_DP = sizeDP; - if (mAdapter != null) { - updateAll(sizeDP); - } - } - } - - public void setScaleEnable(boolean enable) { - if (enable) { - addOnItemTouchListener(touchListener); - } else { - removeOnItemTouchListener(touchListener); - } - } - - public void updateAll(float textSize) { - LayoutManager manager = getLayoutManager(); - - int count = manager.getChildCount(); - - for (int i = 0; i < count; i++) { - View view = manager.getChildAt(i); - loop(view, textSize); - } - } - - private void loop(View view, float textSize) { - if (view instanceof JsonItemView) { - JsonItemView group = (JsonItemView) view; - - group.setTextSize(textSize); - - int childCount = group.getChildCount(); - - for (int i = 0; i < childCount; i++) { - View view1 = group.getChildAt(i); - loop(view1, textSize); - } - } - } - - int mode; - float oldDist; - - private void zoom(float f) { - setTextSize(BaseJsonViewerAdapter.TEXT_SIZE_DP * f); - } - - private float spacing(MotionEvent event) { - float x = event.getX(0) - event.getX(1); - float y = event.getY(0) - event.getY(1); - return (float) Math.sqrt(x * x + y * y); - } - - private OnItemTouchListener touchListener = new OnItemTouchListener() { - @Override - public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent event) { - switch (event.getAction() & event.getActionMasked()) { - case MotionEvent.ACTION_DOWN: - mode = 1; - break; - case MotionEvent.ACTION_UP: - mode = 0; - break; - case MotionEvent.ACTION_POINTER_UP: - mode -= 1; - break; - case MotionEvent.ACTION_POINTER_DOWN: - oldDist = spacing(event); - mode += 1; - break; - - case MotionEvent.ACTION_MOVE: - if (mode >= 2) { - float newDist = spacing(event); - if (Math.abs(newDist - oldDist) > 0.5f) { - zoom(newDist / oldDist); - oldDist = newDist; - } - } - break; - } - return false; - } - - @Override - public void onTouchEvent(RecyclerView rv, MotionEvent event) { - - } - - @Override - public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { - - } - }; -} diff --git a/libs/jsonviewer/src/main/java/com/yuyh/jsonviewer/library/adapter/BaseJsonViewerAdapter.java b/libs/jsonviewer/src/main/java/com/yuyh/jsonviewer/library/adapter/BaseJsonViewerAdapter.java deleted file mode 100644 index 3554528..0000000 --- a/libs/jsonviewer/src/main/java/com/yuyh/jsonviewer/library/adapter/BaseJsonViewerAdapter.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.yuyh.jsonviewer.library.adapter; - -import android.text.style.ForegroundColorSpan; -import androidx.recyclerview.widget.RecyclerView; - -/** - * Created by yuyuhang on 2017/11/30. - */ -public abstract class BaseJsonViewerAdapter extends RecyclerView.Adapter { - - public static int KEY_COLOR = 0xFF922799; - public static int TEXT_COLOR = 0xFF3AB54A; - public static int NUMBER_COLOR = 0xFF25AAE2; - public static int BOOLEAN_COLOR = 0xFFF98280; - public static int URL_COLOR = 0xFF66D2D5; - public static int NULL_COLOR = 0xFFEF5935; - public static int BRACES_COLOR = 0xFF4A555F; - - public static float TEXT_SIZE_DP = 12; -} diff --git a/libs/jsonviewer/src/main/java/com/yuyh/jsonviewer/library/adapter/JsonViewerAdapter.java b/libs/jsonviewer/src/main/java/com/yuyh/jsonviewer/library/adapter/JsonViewerAdapter.java deleted file mode 100644 index 520268a..0000000 --- a/libs/jsonviewer/src/main/java/com/yuyh/jsonviewer/library/adapter/JsonViewerAdapter.java +++ /dev/null @@ -1,287 +0,0 @@ -package com.yuyh.jsonviewer.library.adapter; - -import android.text.SpannableStringBuilder; -import android.text.Spanned; -import android.text.style.ForegroundColorSpan; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; - -import com.yuyh.jsonviewer.library.utils.Utils; -import com.yuyh.jsonviewer.library.view.JsonItemView; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.json.JSONTokener; - -/** - * Created by yuyuhang on 2017/11/29. - */ -public class JsonViewerAdapter extends BaseJsonViewerAdapter { - - private String jsonStr; - - private JSONObject mJSONObject; - private JSONArray mJSONArray; - - public JsonViewerAdapter(String jsonStr) { - this.jsonStr = jsonStr; - - Object object = null; - try { - object = new JSONTokener(jsonStr).nextValue(); - } catch (JSONException e) { - e.printStackTrace(); - } - if (object instanceof JSONObject) { - mJSONObject = (JSONObject) object; - } else if (object instanceof JSONArray) { - mJSONArray = (JSONArray) object; - } else { - throw new IllegalArgumentException("jsonStr is illegal."); - } - } - - public JsonViewerAdapter(JSONObject jsonObject) { - this.mJSONObject = jsonObject; - if (mJSONObject == null) { - throw new IllegalArgumentException("jsonObject can not be null."); - } - } - - public JsonViewerAdapter(JSONArray jsonArray) { - this.mJSONArray = jsonArray; - if (mJSONArray == null) { - throw new IllegalArgumentException("jsonArray can not be null."); - } - } - - @Override - public JsonItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - return new JsonItemViewHolder(new JsonItemView(parent.getContext())); - } - - @Override - public void onBindViewHolder(JsonItemViewHolder holder, int position) { - JsonItemView itemView = holder.itemView; - itemView.setTextSize(TEXT_SIZE_DP); - itemView.setRightColor(BRACES_COLOR); - if (mJSONObject != null) { - if (position == 0) { - itemView.hideLeft(); - itemView.hideIcon(); - itemView.showRight("{"); - return; - } else if (position == getItemCount() - 1) { - itemView.hideLeft(); - itemView.hideIcon(); - itemView.showRight("}"); - return; - } else if (mJSONObject.names() == null) { - return; - } - - String key = mJSONObject.names().optString(position - 1); // 遍历key - Object value = mJSONObject.opt(key); - if (position < getItemCount() - 2) { - handleJsonObject(key, value, itemView, true, 1); - } else { - handleJsonObject(key, value, itemView, false, 1); // 最后一组,结尾不需要逗号 - } - } - - if (mJSONArray != null) { - if (position == 0) { - itemView.hideLeft(); - itemView.hideIcon(); - itemView.showRight("["); - return; - } else if (position == getItemCount() - 1) { - itemView.hideLeft(); - itemView.hideIcon(); - itemView.showRight("]"); - return; - } - - Object value = mJSONArray.opt(position - 1); // 遍历array - if (position < getItemCount() - 2) { - handleJsonArray(value, itemView, true, 1); - } else { - handleJsonArray(value, itemView, false, 1); // 最后一组,结尾不需要逗号 - } - } - } - - @Override - public int getItemCount() { - if (mJSONObject != null) { - if (mJSONObject.names() != null) { - return mJSONObject.names().length() + 2; - } else { - return 2; - } - } - if (mJSONArray != null) { - return mJSONArray.length() + 2; - } - return 0; - } - - /** - * 处理 value 上级为 JsonObject 的情况,value有key - * - * @param value - * @param key - * @param itemView - * @param appendComma - * @param hierarchy - */ - private void handleJsonObject(String key, Object value, JsonItemView itemView, boolean appendComma, int hierarchy) { - SpannableStringBuilder keyBuilder = new SpannableStringBuilder(Utils.getHierarchyStr(hierarchy)); - keyBuilder.append("\"").append(key).append("\"").append(":"); - keyBuilder.setSpan(new ForegroundColorSpan(KEY_COLOR), 0, keyBuilder.length() - 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - keyBuilder.setSpan(new ForegroundColorSpan(BRACES_COLOR), keyBuilder.length() - 1, keyBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - - itemView.showLeft(keyBuilder); - - handleValue(value, itemView, appendComma, hierarchy); - } - - /** - * 处理 value 上级为 JsonArray 的情况,value无key - * - * @param value - * @param itemView - * @param appendComma 结尾是否需要逗号(最后一组 value 不需要逗号) - * @param hierarchy 缩进层级 - */ - private void handleJsonArray(Object value, JsonItemView itemView, boolean appendComma, int hierarchy) { - itemView.showLeft(new SpannableStringBuilder(Utils.getHierarchyStr(hierarchy))); - - handleValue(value, itemView, appendComma, hierarchy); - } - - /** - * @param value - * @param itemView - * @param appendComma 结尾是否需要逗号(最后一组 key:value 不需要逗号) - * @param hierarchy 缩进层级 - */ - private void handleValue(Object value, JsonItemView itemView, boolean appendComma, int hierarchy) { - SpannableStringBuilder valueBuilder = new SpannableStringBuilder(); - if (value instanceof Number) { - valueBuilder.append(value.toString()); - valueBuilder.setSpan(new ForegroundColorSpan(NUMBER_COLOR), 0, valueBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - } else if (value instanceof Boolean) { - valueBuilder.append(value.toString()); - valueBuilder.setSpan(new ForegroundColorSpan(BOOLEAN_COLOR), 0, valueBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - } else if (value instanceof JSONObject) { - itemView.showIcon(true); - valueBuilder.append("Object{...}"); - valueBuilder.setSpan(new ForegroundColorSpan(BRACES_COLOR), 0, valueBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - itemView.setIconClickListener(new JsonItemClickListener(value, itemView, appendComma, hierarchy + 1)); - } else if (value instanceof JSONArray) { - itemView.showIcon(true); - valueBuilder.append("Array[").append(String.valueOf(((JSONArray) value).length())).append("]"); - int len = valueBuilder.length(); - valueBuilder.setSpan(new ForegroundColorSpan(BRACES_COLOR), 0, 6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - valueBuilder.setSpan(new ForegroundColorSpan(NUMBER_COLOR), 6, len - 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - valueBuilder.setSpan(new ForegroundColorSpan(BRACES_COLOR), len - 1, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - itemView.setIconClickListener(new JsonItemClickListener(value, itemView, appendComma, hierarchy + 1)); - } else if (value instanceof String) { - itemView.hideIcon(); - valueBuilder.append("\"").append(value.toString()).append("\""); - if (Utils.isUrl(value.toString())) { - valueBuilder.setSpan(new ForegroundColorSpan(TEXT_COLOR), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - valueBuilder.setSpan(new ForegroundColorSpan(URL_COLOR), 1, valueBuilder.length() - 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - valueBuilder.setSpan(new ForegroundColorSpan(TEXT_COLOR), valueBuilder.length() - 1, valueBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - } else { - valueBuilder.setSpan(new ForegroundColorSpan(TEXT_COLOR), 0, valueBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - } - } else if (valueBuilder.length() == 0 || value == null) { - itemView.hideIcon(); - valueBuilder.append("null"); - valueBuilder.setSpan(new ForegroundColorSpan(NULL_COLOR), 0, valueBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - } - if (appendComma) { - valueBuilder.append(","); - } - - itemView.showRight(valueBuilder); - } - - class JsonItemClickListener implements View.OnClickListener { - - private Object value; - private JsonItemView itemView; - private boolean appendComma; - private int hierarchy; - - private boolean isCollapsed = true; - private boolean isJsonArray; - - JsonItemClickListener(Object value, JsonItemView itemView, boolean appendComma, int hierarchy) { - this.value = value; - this.itemView = itemView; - this.appendComma = appendComma; - this.hierarchy = hierarchy; - this.isJsonArray = value != null && value instanceof JSONArray; - } - - @Override - public void onClick(View view) { - if (itemView.getChildCount() == 1) { // 初始(折叠) --> 展开"" - isCollapsed = false; - itemView.showIcon(false); - itemView.setTag(itemView.getRightText()); - itemView.showRight(isJsonArray ? "[" : "{"); - JSONArray array = isJsonArray ? (JSONArray) value : ((JSONObject) value).names(); - for (int i = 0; array != null && i < array.length(); i++) { - JsonItemView childItemView = new JsonItemView(itemView.getContext()); - childItemView.setTextSize(TEXT_SIZE_DP); - childItemView.setRightColor(BRACES_COLOR); - Object childValue = array.opt(i); - if (isJsonArray) { - handleJsonArray(childValue, childItemView, i < array.length() - 1, hierarchy); - } else { - handleJsonObject((String) childValue, ((JSONObject) value).opt((String) childValue), childItemView, i < array.length() - 1, hierarchy); - } - itemView.addViewNoInvalidate(childItemView); - } - - JsonItemView childItemView = new JsonItemView(itemView.getContext()); - childItemView.setTextSize(TEXT_SIZE_DP); - childItemView.setRightColor(BRACES_COLOR); - StringBuilder builder = new StringBuilder(Utils.getHierarchyStr(hierarchy - 1)); - builder.append(isJsonArray ? "]" : "}").append(appendComma ? "," : ""); - childItemView.showRight(builder); - itemView.addViewNoInvalidate(childItemView); - itemView.requestLayout(); - itemView.invalidate(); - } else { // 折叠 <--> 展开 - CharSequence temp = itemView.getRightText(); - itemView.showRight((CharSequence) itemView.getTag()); - itemView.setTag(temp); - itemView.showIcon(!isCollapsed); - for (int i = 1; i < itemView.getChildCount(); i++) { - itemView.getChildAt(i).setVisibility(isCollapsed ? View.VISIBLE : View.GONE); - } - isCollapsed = !isCollapsed; - } - } - } - - class JsonItemViewHolder extends RecyclerView.ViewHolder { - - JsonItemView itemView; - - JsonItemViewHolder(JsonItemView itemView) { - super(itemView); - setIsRecyclable(false); - this.itemView = itemView; - } - } -} diff --git a/libs/jsonviewer/src/main/java/com/yuyh/jsonviewer/library/utils/Utils.java b/libs/jsonviewer/src/main/java/com/yuyh/jsonviewer/library/utils/Utils.java deleted file mode 100644 index 1cc59bd..0000000 --- a/libs/jsonviewer/src/main/java/com/yuyh/jsonviewer/library/utils/Utils.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.yuyh.jsonviewer.library.utils; - -import java.util.regex.Pattern; - -/** - * Created by yuyuhang on 2017/11/30. - */ -public class Utils { - - private static Pattern urlPattern = Pattern.compile("^((https|http|ftp|rtsp|mms)?://)" - + "?(([0-9a-z_!~*'().&=+$%-]+: )?[0-9a-z_!~*'().&=+$%-]+@)?" //ftp的user@ - + "(([0-9]{1,3}\\.){3}[0-9]{1,3}" // IP形式的URL- 199.194.52.184 - + "|" // 允许IP和DOMAIN(域名) - + "([0-9a-z_!~*'()-]+\\.)*" // 域名- www. - + "([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\\." // 二级域名 - + "[a-z]{2,6})" // first level domain- .com or .museum - + "(:[0-9]{1,4})?" // 端口- :80 - + "((/?)|" // a slash isn't required if there is no file name - + "(/[0-9a-z_!~*'().;?:@&=+$,%#-]+)+/?)$"); - - /** - * 判断字符串是否是url - * - * @param str - * @return - */ - public static boolean isUrl(String str) { - return urlPattern.matcher(str).matches(); - } - - /** - * json 格式化缩进(格式化前不能有缩进,最好是格式化从服务端下发的) - * - * @param jsonStr - * @return - */ - public static String jsonFormat(String jsonStr) { - if (jsonStr == null) return ""; - int level = 0; - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < jsonStr.length(); i++) { - char c = jsonStr.charAt(i); - if (level > 0 && '\n' == builder.charAt(builder.length() - 1)) { - builder.append(getHierarchyStr(level)); - } - switch (c) { - case '{': - case '[': - builder.append(c).append("\n"); - level++; - break; - case ',': - builder.append(c).append("\n"); - break; - case '}': - case ']': - builder.append("\n"); - level--; - builder.append(getHierarchyStr(level)); - builder.append(c); - break; - default: - builder.append(c); - break; - } - } - - return builder.toString(); - } - - /** - * 对应层级前面所需的空格数 - * - * @param hierarchy 缩进层级 - * @return - */ - public static String getHierarchyStr(int hierarchy) { - StringBuilder levelStr = new StringBuilder(); - for (int levelI = 0; levelI < hierarchy; levelI++) { - levelStr.append(" "); - } - return levelStr.toString(); - } - -} diff --git a/libs/jsonviewer/src/main/java/com/yuyh/jsonviewer/library/view/JsonItemView.java b/libs/jsonviewer/src/main/java/com/yuyh/jsonviewer/library/view/JsonItemView.java deleted file mode 100644 index 05e6f26..0000000 --- a/libs/jsonviewer/src/main/java/com/yuyh/jsonviewer/library/view/JsonItemView.java +++ /dev/null @@ -1,133 +0,0 @@ -package com.yuyh.jsonviewer.library.view; - -import android.content.Context; -import android.util.AttributeSet; -import android.util.TypedValue; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import androidx.annotation.Nullable; - -import com.yuyh.jsonviewer.library.R; -import com.yuyh.jsonviewer.library.adapter.BaseJsonViewerAdapter; - -/** - * Created by yuyuhang on 2017/11/29. - */ -public class JsonItemView extends LinearLayout { - - public static int TEXT_SIZE_DP = 12; - - private Context mContext; - - private TextView mTvLeft, mTvRight; - private ImageView mIvIcon; - - public JsonItemView(Context context) { - this(context, null); - } - - public JsonItemView(Context context, @Nullable AttributeSet attrs) { - this(context, attrs, 0); - } - - public JsonItemView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - - mContext = context; - - initView(); - } - - private void initView() { - setOrientation(VERTICAL); - LayoutInflater.from(mContext).inflate(R.layout.jsonviewer_layout_item_view, this, true); - - mTvLeft = findViewById(R.id.tv_left); - mTvRight = findViewById(R.id.tv_right); - mIvIcon = findViewById(R.id.iv_icon); - } - - public void setTextSize(float textSizeDp) { - if (textSizeDp < 12) { - textSizeDp = 12; - } else if (textSizeDp > 30) { - textSizeDp = 30; - } - - TEXT_SIZE_DP = (int) textSizeDp; - - mTvLeft.setTextSize(TEXT_SIZE_DP); - mTvRight.setTextSize(TEXT_SIZE_DP); - mTvRight.setTextColor(BaseJsonViewerAdapter.BRACES_COLOR); - - // align the vertically expand/collapse icon to the text - int textSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, TEXT_SIZE_DP, getResources().getDisplayMetrics()); - - LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) mIvIcon.getLayoutParams(); - layoutParams.height = textSize; - layoutParams.width = textSize; - layoutParams.topMargin = textSize / 5; - - mIvIcon.setLayoutParams(layoutParams); - } - - public void setRightColor(int color) { - mTvRight.setTextColor(color); - } - - public void hideLeft() { - mTvLeft.setVisibility(GONE); - } - - public void showLeft(CharSequence text) { - mTvLeft.setVisibility(VISIBLE); - if (text != null) { - mTvLeft.setText(text); - } - } - - public void hideRight() { - mTvRight.setVisibility(GONE); - } - - public void showRight(CharSequence text) { - mTvRight.setVisibility(VISIBLE); - if (text != null) { - mTvRight.setText(text); - } - } - - public CharSequence getRightText() { - return mTvRight.getText(); - } - - public void hideIcon() { - mIvIcon.setVisibility(GONE); - } - - public void showIcon(boolean isPlus) { - mIvIcon.setVisibility(VISIBLE); - mIvIcon.setImageResource(isPlus ? R.drawable.jsonviewer_plus : R.drawable.jsonviewer_minus); - mIvIcon.setContentDescription(getResources().getString(isPlus ? R.string.jsonViewer_icon_plus : R.string.jsonViewer_icon_minus)); - } - - public void setIconClickListener(OnClickListener listener) { - mIvIcon.setOnClickListener(listener); - } - - public void addViewNoInvalidate(View child) { - ViewGroup.LayoutParams params = child.getLayoutParams(); - if (params == null) { - params = generateDefaultLayoutParams(); - if (params == null) { - throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null"); - } - } - addViewInLayout(child, -1, params); - } -} diff --git a/libs/jsonviewer/src/main/res/drawable/jsonviewer_minus.xml b/libs/jsonviewer/src/main/res/drawable/jsonviewer_minus.xml deleted file mode 100644 index d7ec09a..0000000 --- a/libs/jsonviewer/src/main/res/drawable/jsonviewer_minus.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/libs/jsonviewer/src/main/res/drawable/jsonviewer_plus.xml b/libs/jsonviewer/src/main/res/drawable/jsonviewer_plus.xml deleted file mode 100644 index b41fc31..0000000 --- a/libs/jsonviewer/src/main/res/drawable/jsonviewer_plus.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/libs/jsonviewer/src/main/res/layout/jsonviewer_layout_item_view.xml b/libs/jsonviewer/src/main/res/layout/jsonviewer_layout_item_view.xml deleted file mode 100644 index 4887a0e..0000000 --- a/libs/jsonviewer/src/main/res/layout/jsonviewer_layout_item_view.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/libs/jsonviewer/src/main/res/values/strings.xml b/libs/jsonviewer/src/main/res/values/strings.xml deleted file mode 100644 index c2e6692..0000000 --- a/libs/jsonviewer/src/main/res/values/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - expand - collapse - diff --git a/settings.gradle b/settings.gradle index 92b831f..13d6585 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,7 +2,4 @@ include ':BackupApp' rootProject.name = "Backup" include ':BackupAPI' -project(':BackupAPI').projectDir = new File('BackupAPI/BackupAPI') - -include ':jsonviewer' -project(':jsonviewer').projectDir = new File('libs/jsonviewer') \ No newline at end of file +project(':BackupAPI').projectDir = new File('BackupAPI/BackupAPI') \ No newline at end of file