diff --git a/.cirrus.yml b/.cirrus.yml deleted file mode 100644 index 7f145d11..00000000 --- a/.cirrus.yml +++ /dev/null @@ -1,34 +0,0 @@ -connected_check_task: - name: Run Android instrumented tests - env: - API_LEVEL: 23 - TARGET: default - ARCH: x86 - CC_TEST_REPORTER_ID: ENCRYPTED[!b71004b17b92e8fb7a3fecc3e2a9cc28c4e5f07f55e2f20cdfc641c57487cd21c7df6e7930318f8d87bc4675e63b260d!] - container: - image: reactivecircus/android-emulator-23:latest - kvm: true - cpu: 8 - memory: 16G - create_device_script: - echo no | avdmanager create avd --force --name "api-${API_LEVEL}" --abi "${TARGET}/${ARCH}" --package "system-images;android-${API_LEVEL};${TARGET};${ARCH}" - start_emulator_background_script: - $ANDROID_HOME/emulator/emulator -avd "api-${API_LEVEL}" -no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim -camera-back none - wait_for_emulator_script: - - chmod +x android-wait-for-emulator.sh - - ./android-wait-for-emulator.sh - disable_animations_script: | - adb shell settings put global window_animation_scale 0.0 - adb shell settings put global transition_animation_scale 0.0 - adb shell settings put global animator_duration_scale 0.0 - prepare_codeclimate_script: - - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter - - chmod +x ./cc-test-reporter - - ./cc-test-reporter before-build - run_instrumented_tests_script: - ./gradlew build connectedCheck jacocoTestReport - report_codeclimate_script: - # Report test coverage to Code Climate - - export JACOCO_SOURCE_PATH=app/src/main/java/ - - ./cc-test-reporter format-coverage ./app/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml --input-type jacoco - - ./cc-test-reporter upload-coverage diff --git a/.fdroid.yml.template b/.fdroid.yml.template new file mode 100644 index 00000000..84478b87 --- /dev/null +++ b/.fdroid.yml.template @@ -0,0 +1,29 @@ +Categories: + - Internet +License: GPL-3.0-or-later +AuthorName: PixelDroid team +AuthorEmail: contact@pixeldroid.org +WebSite: https://pixeldroid.org/ +SourceCode: https://gitlab.shinice.net/pixeldroid/PixelDroid +IssueTracker: https://gitlab.shinice.net/pixeldroid/PixelDroid/issues +Translation: https://weblate.pixeldroid.org/projects/pixeldroid/ +Changelog: https://gitlab.shinice.net/pixeldroid/PixelDroid/-/releases +Liberapay: PixelDroid + +AutoName: PixelDroid + +RepoType: git +Repo: https://gitlab.shinice.net/pixeldroid/PixelDroid.git + +Builds: + - versionName: ${versionName} + versionCode: ${versionCode} + commit: HEAD + subdir: app + gradle: + - yes + +AutoUpdateMode: Version %v +UpdateCheckMode: Tags +CurrentVersion: 1.0.beta1 +CurrentVersionCode: 1 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..0cd0b0a0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +app/src/main/assets/licenses.html linguist-generated diff --git a/.gitignore b/.gitignore index d879603d..1d76c5b1 100644 --- a/.gitignore +++ b/.gitignore @@ -14,5 +14,6 @@ .cxx .idea app/release +app/debug app/lint lint diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f24f203f..a2e634e1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,6 +7,14 @@ variables: TARGET: "default" +before_script: + - export GRADLE_USER_HOME=`pwd`/.gradle + +cache: + paths: + - .gradle/wrapper + - .gradle/caches + # Basic android and gradle stuff # Check linting lintDebug: @@ -52,6 +60,62 @@ emulatorTest: - cat app/build/reports/jacoco/jacocoTestReport/html/index.html | grep -o 'Total[^%]*%' artifacts: + when: always paths: - ./app/build/reports/jacoco/jacocoTestReport/ expire_in: 1 week + + +fdroid build: + image: registry.gitlab.com/fdroid/ci-images-client:latest + allow_failure: true + artifacts: + paths: + - unsigned/ + when: always + only: + - tags + cache: + key: "$CI_JOB_NAME" + paths: + - .gradle + script: + # Put the correct versionName and versionCode in the .fdroid.yml + - sed -e "s/\${versionName}/$(grep "versionName " app/build.gradle | awk '{print $2}')/" -e "s/\${versionCode}/$(grep "versionCode" app/build.gradle | awk '{print $2}')/" .fdroid.yml.template > .fdroid.yml + - rm .fdroid.yml.template + - test -d build || mkdir build + - test -d fdroidserver || mkdir fdroidserver + - git ls-remote https://gitlab.com/fdroid/fdroidserver.git master + - curl --silent https://gitlab.com/fdroid/fdroidserver/-/archive/master/fdroidserver-master.tar.gz + | tar -xz --directory=fdroidserver --strip-components=1 + - export PATH="`pwd`/fdroidserver:$PATH" + - export PYTHONPATH="$CI_PROJECT_DIR/fdroidserver:$CI_PROJECT_DIR/fdroidserver/examples" + - export PYTHONUNBUFFERED=true + + - bash fdroidserver/buildserver/setup-env-vars $ANDROID_HOME + - adduser --disabled-password --gecos "" vagrant + - ln -s $CI_PROJECT_DIR/fdroidserver /home/vagrant/fdroidserver + - mkdir -p /vagrant/cache + - wget -q https://services.gradle.org/distributions/gradle-5.6.2-bin.zip + --output-document=/vagrant/cache/gradle-5.6.2-bin.zip + - bash fdroidserver/buildserver/provision-gradle + - bash fdroidserver/buildserver/provision-apt-get-install http://deb.debian.org/debian + - source /etc/profile.d/bsenv.sh + - apt-get dist-upgrade + + # install fdroidserver from git, with deps from Debian, until fdroidserver + # is stable enough to include all the things needed here + - apt-get install -t stretch-backports + fdroidserver + python3-asn1crypto + python3-ruamel.yaml + yamllint + - apt-get purge fdroidserver + + - export GRADLE_USER_HOME=$PWD/.gradle + # each `fdroid build --on-server` run expects sudo, then uninstalls it + - set -x + - apt-get install sudo + - fdroid fetchsrclibs --verbose + # this builds the latest version of the app from its source dir, using the build recipe in .fdroid.yml + - fdroid build --verbose --on-server --no-tarball diff --git a/README.md b/README.md index 542a6bcf..e6d6cf4b 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,13 @@ # PixelDroid ![Pixeldroid project logo](pixeldroid_logo.png) -Free (as in freedom) Android client for Pixelfed, the federated image sharing platform. +Free (as in freedom) Android client for Pixelfed, the federated image sharing platform. Licensed under the GNU General Public License version 3 (or any later version) [![Build Status](https://gitlab.shinice.net/pixeldroid/PixelDroid/badges/master/pipeline.svg)](https://gitlab.shinice.net/pixeldroid/PixelDroid/pipelines) [![Maintainability](https://api.codeclimate.com/v1/badges/a4f1747dc60b96eb74df/maintainability)](https://codeclimate.com/github/H-PixelDroid/PixelDroid/maintainability) [![Translation status](https://weblate.pixeldroid.org/widgets/pixeldroid/-/pixeldroid/svg-badge.svg)](https://weblate.pixeldroid.org/engage/pixeldroid/?utm_source=widget) - + + + Get it on F-Droid + ## 🔧 Compiling the code yourself If you want to try out PixelDroid on your own device, you can compile the source code yourself. To do that you can install [Android Studio](https://developer.android.com/studio/). diff --git a/Screenshots/featureGraphic.xcf b/Screenshots/featureGraphic.xcf new file mode 100644 index 00000000..38a68a75 Binary files /dev/null and b/Screenshots/featureGraphic.xcf differ diff --git a/app/build.gradle b/app/build.gradle index 38666685..4e01539f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,6 +7,9 @@ apply plugin: 'kotlin-android' apply plugin: 'kotlin-kapt' apply plugin: 'jacoco' +// Force latest version of Jacoco, initially done to resolve https://github.com/jacoco/jacoco/issues/1155 +jacoco.toolVersion = "0.8.7" + android { @@ -21,11 +24,11 @@ android { freeCompilerArgs += ["-Xopt-in=kotlin.RequiresOptIn"] } defaultConfig { - applicationId "com.h.pixeldroid" + applicationId "org.pixeldroid.app" minSdkVersion 23 targetSdkVersion 30 - versionCode 10 - versionName "1.0.alpha9" + versionCode 3 + versionName "1.0.beta3" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunnerArguments clearPackageData: 'true' @@ -36,15 +39,15 @@ android { sourceSets { main.java.srcDirs += 'src/main/java' test.java.srcDirs += 'src/test/java' + staging.res.srcDirs += 'src/debug/res' androidTest.java.srcDirs += 'src/androidTest/java' } testBuildType "staging" - - buildTypes { debug { - + applicationIdSuffix '.debug' + versionNameSuffix "-debug" } staging { initWith debug @@ -61,12 +64,12 @@ android { localProperties.load(new FileInputStream(rootProject.file("local.properties"))) } - buildConfigField "String", "USER_ID", System.getenv("USER_ID") ?: localProperties['USER_ID'] - buildConfigField "String", "INSTANCE_URI", System.getenv("INSTANCE_URI") ?: localProperties['INSTANCE_URI'] - buildConfigField "String", "ACCESS_TOKEN", System.getenv("ACCESS_TOKEN") ?: localProperties['ACCESS_TOKEN'] - buildConfigField "String", "REFRESH_TOKEN", System.getenv("REFRESH_TOKEN") ?: localProperties['REFRESH_TOKEN'] - buildConfigField "String", "CLIENT_ID", System.getenv("CLIENT_ID") ?: localProperties['CLIENT_ID'] - buildConfigField "String", "CLIENT_SECRET", System.getenv("CLIENT_SECRET") ?: localProperties['CLIENT_SECRET'] + buildConfigField "String", "USER_ID", System.getenv("USER_ID") ?: localProperties['USER_ID'] ?: "" + buildConfigField "String", "INSTANCE_URI", System.getenv("INSTANCE_URI") ?: localProperties['INSTANCE_URI'] ?: "" + buildConfigField "String", "ACCESS_TOKEN", System.getenv("ACCESS_TOKEN") ?: localProperties['ACCESS_TOKEN'] ?: "" + buildConfigField "String", "REFRESH_TOKEN", System.getenv("REFRESH_TOKEN") ?: localProperties['REFRESH_TOKEN'] ?: "" + buildConfigField "String", "CLIENT_ID", System.getenv("CLIENT_ID") ?: localProperties['CLIENT_ID'] ?: "" + buildConfigField "String", "CLIENT_SECRET", System.getenv("CLIENT_SECRET") ?: localProperties['CLIENT_SECRET'] ?: "" } release { minifyEnabled true @@ -74,6 +77,14 @@ android { proguardFiles 'proguard-rules.pro' } } + /** + * Make a string with the application_id (available in xml etc) + */ + android.applicationVariants.all { variant -> + variant.resValue 'string', 'application_id', variant.applicationId + } + + testOptions { animationsDisabled true @@ -92,37 +103,38 @@ dependencies { /** * AndroidX dependencies: */ - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'androidx.core:core-ktx:1.3.2' + implementation 'androidx.appcompat:appcompat:1.3.0' + implementation 'androidx.core:core-ktx:1.5.0' implementation 'androidx.preference:preference-ktx:1.1.1' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' - implementation 'androidx.navigation:navigation-fragment-ktx:2.3.4' - implementation 'androidx.navigation:navigation-ui-ktx:2.3.4' + implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5' + implementation 'androidx.navigation:navigation-ui-ktx:2.3.5' implementation "androidx.browser:browser:1.3.0" - implementation 'androidx.recyclerview:recyclerview:1.1.0' + implementation 'androidx.recyclerview:recyclerview:1.2.1' implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" - implementation 'androidx.navigation:navigation-fragment-ktx:2.3.4' - implementation 'androidx.navigation:navigation-ui-ktx:2.3.4' - implementation 'androidx.paging:paging-runtime-ktx:3.0.0-beta02' - implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.0' - implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:2.3.0' - implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.3.0" - implementation "androidx.lifecycle:lifecycle-common-java8:2.3.0" - implementation "androidx.annotation:annotation:1.1.0" + implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5' + implementation 'androidx.navigation:navigation-ui-ktx:2.3.5' + implementation 'androidx.paging:paging-runtime-ktx:3.0.0' + implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1' + implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:2.3.1' + implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-common-java8:2.3.1" + implementation "androidx.annotation:annotation:1.2.0" implementation 'androidx.gridlayout:gridlayout:1.0.0' - implementation "androidx.activity:activity-ktx:1.2.1" + implementation "androidx.activity:activity-ktx:1.2.3" + implementation 'androidx.fragment:fragment-ktx:1.3.5' // Use the most recent version of CameraX - def cameraX_version = '1.0.0-rc03' + def cameraX_version = '1.0.0' implementation "androidx.camera:camera-core:${cameraX_version}" implementation "androidx.camera:camera-camera2:${cameraX_version}" // CameraX Lifecycle library implementation "androidx.camera:camera-lifecycle:$cameraX_version" // CameraX View class - implementation 'androidx.camera:camera-view:1.0.0-alpha22' + implementation 'androidx.camera:camera-view:1.0.0-alpha25' - def room_version = "2.3.0-beta03" + def room_version = "2.3.0" implementation "androidx.room:room-runtime:$room_version" kapt "androidx.room:room-compiler:$room_version" implementation "androidx.room:room-ktx:$room_version" @@ -136,17 +148,17 @@ dependencies { implementation 'com.google.android.material:material:1.3.0' //Dagger (dependency injection) - implementation 'com.google.dagger:dagger-android:2.30.1' - implementation 'com.google.dagger:dagger-android-support:2.30.1' + implementation 'com.google.dagger:dagger-android:2.37' + implementation 'com.google.dagger:dagger-android-support:2.37' // if you use the support libraries - kapt 'com.google.dagger:dagger-android-processor:2.30.1' - kapt 'com.google.dagger:dagger-compiler:2.30.1' + kapt 'com.google.dagger:dagger-android-processor:2.37' + kapt 'com.google.dagger:dagger-compiler:2.37' - implementation 'com.squareup.okhttp3:okhttp:4.9.0' + implementation 'com.squareup.okhttp3:okhttp:4.9.1' implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0' - implementation 'io.reactivex.rxjava2:rxjava:2.2.20' + implementation 'io.reactivex.rxjava2:rxjava:2.2.21' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation 'com.github.connyduck:sparkbutton:4.1.0' @@ -154,26 +166,26 @@ dependencies { implementation 'info.androidhive:imagefilters:1.0.7' implementation 'com.github.yalantis:ucrop:2.2.6-native' - implementation("com.github.bumptech.glide:glide:4.11.0") { + implementation('com.github.bumptech.glide:glide:4.12.0') { exclude group: "com.android.support" } - implementation "com.github.bumptech.glide:okhttp-integration:4.11.0" - implementation("com.github.bumptech.glide:recyclerview-integration:4.11.0") { + implementation 'com.github.bumptech.glide:okhttp-integration:4.12.0' + implementation('com.github.bumptech.glide:recyclerview-integration:4.12.0') { // Excludes the support library because it's already included by Glide. transitive = false } - kapt 'com.github.bumptech.glide:compiler:4.11.0' + kapt 'com.github.bumptech.glide:compiler:4.12.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0' - implementation "com.mikepenz:materialdrawer:8.1.8" + implementation 'com.mikepenz:materialdrawer:8.4.1' // Add for NavController support - implementation "com.mikepenz:materialdrawer-nav:8.1.5" + implementation 'com.mikepenz:materialdrawer-nav:8.4.0' //iconics - implementation "com.mikepenz:iconics-core:5.0.3" - implementation "com.mikepenz:materialdrawer-iconics:8.1.8" + implementation "com.mikepenz:iconics-core:5.2.8" + implementation 'com.mikepenz:materialdrawer-iconics:8.4.1' implementation "com.mikepenz:iconics-views:5.0.3" implementation 'com.mikepenz:google-material-typeface:3.0.1.4.original-kotlin@aar' @@ -190,13 +202,15 @@ dependencies { // debugImplementation required vs testImplementation: https://issuetracker.google.com/issues/128612536 //noinspection FragmentGradleConfiguration - stagingImplementation("androidx.fragment:fragment-testing:1.3.1") { + stagingImplementation("androidx.fragment:fragment-testing:1.3.5") { exclude group:'androidx.test', module:'monitor' } + //stagingImplementation 'com.squareup.leakcanary:leakcanary-android:2.7' + testImplementation 'com.github.tomakehurst:wiremock-jre8:2.27.2' testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0" - testImplementation 'junit:junit:4.13.1' + testImplementation 'junit:junit:4.13.2' testImplementation "androidx.room:room-testing:$room_version" @@ -227,10 +241,10 @@ task jacocoTestReport(type: JacocoReport, dependsOn: ['connectedStagingAndroidTe } def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*'] - def kotlinDebugTree = fileTree(dir: "$project.buildDir/tmp/kotlin-classes/debug", excludes: fileFilter) + def kotlinTree = fileTree(dir: "$project.buildDir/tmp/kotlin-classes/staging", excludes: fileFilter) def mainSrc = "$project.projectDir/src/main/java" getSourceDirectories().from(files([mainSrc])) - getClassDirectories().from(files([kotlinDebugTree])) + getClassDirectories().from(files([kotlinTree])) getExecutionData().from(fileTree(dir: project.buildDir, includes: [ 'outputs/code_coverage/stagingAndroidTest/connected/*coverage.ec', @@ -238,4 +252,4 @@ task jacocoTestReport(type: JacocoReport, dependsOn: ['connectedStagingAndroidTe 'jacoco/testStagingUnitTest.exec' ])) -} \ No newline at end of file +} diff --git a/app/licenses.yml b/app/licenses.yml index 7f0f194d..86b165e6 100644 --- a/app/licenses.yml +++ b/app/licenses.yml @@ -16,12 +16,12 @@ license: The Apache Software License, Version 2.0 licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt url: https://github.com/mikepenz/MaterialDrawer -- artifact: org.jetbrains.kotlin:kotlin-android-extensions-runtime:+ - name: kotlin-android-extensions-runtime - copyrightHolder: JetBrains s.r.o. and contributors - license: The Apache License, Version 2.0 +- artifact: androidx.startup:startup-runtime:+ + name: startup-runtime + copyrightHolder: Google Inc. + license: The Apache Software License, Version 2.0 licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt - url: https://kotlinlang.org/ + url: https://developer.android.com/jetpack/androidx/releases/startup#1.0.0 - artifact: com.mikepenz:iconics-views:+ name: iconics-views copyrightHolder: Mike Penz and contributors @@ -793,4 +793,4 @@ copyrightHolder: Google Inc license: The Apache Software License, Version 2.0 licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt - url: https://developer.android.com/jetpack/androidx/releases/tracing#1.0.0 \ No newline at end of file + url: https://developer.android.com/jetpack/androidx/releases/tracing#1.0.0 diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 126f20d8..db0002be 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -37,9 +37,9 @@ # APP SPECIFIC OPTIONS # keep members of our model classes, they are used in json de/serialization --keepclassmembers class com.h.pixeldroid.utils.api.objects.* { *; } +-keepclassmembers class org.pixeldroid.app.utils.api.objects.* { *; } --keep public enum com.h.pixeldroid.utils.api.objects.*$** { +-keep public enum org.pixeldroid.app.utils.api.objects.*$** { **[] $VALUES; public *; } diff --git a/app/src/androidTest/java/com/h/pixeldroid/CameraTest.kt b/app/src/androidTest/java/org/pixeldroid/app/CameraTest.kt similarity index 90% rename from app/src/androidTest/java/com/h/pixeldroid/CameraTest.kt rename to app/src/androidTest/java/org/pixeldroid/app/CameraTest.kt index 144cacd5..8df00b14 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/CameraTest.kt +++ b/app/src/androidTest/java/org/pixeldroid/app/CameraTest.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid +package org.pixeldroid.app import android.Manifest import android.content.Context @@ -10,11 +10,11 @@ import androidx.test.core.app.ApplicationProvider import androidx.test.espresso.intent.Intents import androidx.test.espresso.intent.matcher.IntentMatchers import androidx.test.rule.GrantPermissionRule -import com.h.pixeldroid.utils.db.entities.InstanceDatabaseEntity -import com.h.pixeldroid.utils.db.entities.UserDatabaseEntity -import com.h.pixeldroid.postCreation.camera.CameraFragment -import com.h.pixeldroid.testUtility.clearData -import com.h.pixeldroid.testUtility.initDB +import org.pixeldroid.app.utils.db.entities.InstanceDatabaseEntity +import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity +import org.pixeldroid.app.postCreation.camera.CameraFragment +import org.pixeldroid.app.testUtility.clearData +import org.pixeldroid.app.testUtility.initDB import org.hamcrest.CoreMatchers import org.hamcrest.Matcher import org.junit.After diff --git a/app/src/androidTest/java/com/h/pixeldroid/DrawerMenuTest.kt b/app/src/androidTest/java/org/pixeldroid/app/DrawerMenuTest.kt similarity index 93% rename from app/src/androidTest/java/com/h/pixeldroid/DrawerMenuTest.kt rename to app/src/androidTest/java/org/pixeldroid/app/DrawerMenuTest.kt index 8f60e387..81175963 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/DrawerMenuTest.kt +++ b/app/src/androidTest/java/org/pixeldroid/app/DrawerMenuTest.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid +package org.pixeldroid.app import android.content.Context import androidx.test.core.app.ActivityScenario @@ -12,8 +12,9 @@ import androidx.test.espresso.matcher.ViewMatchers.* import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import androidx.test.uiautomator.UiDevice -import com.h.pixeldroid.testUtility.* -import com.h.pixeldroid.utils.db.AppDatabase +import org.hamcrest.Matchers.allOf +import org.pixeldroid.app.testUtility.* +import org.pixeldroid.app.utils.db.AppDatabase import org.junit.After import org.junit.Before import org.junit.Rule @@ -107,8 +108,10 @@ class DrawerMenuTest { // Start the screen of your activity. onView(withText(R.string.menu_account)).perform(click()) // Check that profile activity was opened. + waitForView(R.id.editButton) onView(withId(R.id.editButton)).check(matches(isDisplayed())) val followersText = context.resources.getQuantityString(R.plurals.nb_followers, 2, 2) + waitForView(R.id.nbFollowingTextView, allOf(withId(R.id.nbFollowersTextView), withText(followersText))) onView(withText(followersText)).perform(click()) waitForView(R.id.account_entry_avatar) @@ -120,8 +123,10 @@ class DrawerMenuTest { // Start the screen of your activity. onView(withText(R.string.menu_account)).perform(click()) // Check that profile activity was opened. + waitForView(R.id.editButton) onView(withId(R.id.editButton)).check(matches(isDisplayed())) val followingText = context.resources.getQuantityString(R.plurals.nb_following, 3, 3) + waitForView(R.id.nbFollowingTextView, allOf(withId(R.id.nbFollowingTextView), withText(followingText))) onView(withText(followingText)).perform(click()) waitForView(R.id.account_entry_avatar) diff --git a/app/src/androidTest/java/com/h/pixeldroid/EditPhotoTest.kt b/app/src/androidTest/java/org/pixeldroid/app/EditPhotoTest.kt similarity index 92% rename from app/src/androidTest/java/com/h/pixeldroid/EditPhotoTest.kt rename to app/src/androidTest/java/org/pixeldroid/app/EditPhotoTest.kt index c5868a97..bb7d627a 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/EditPhotoTest.kt +++ b/app/src/androidTest/java/org/pixeldroid/app/EditPhotoTest.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid +package org.pixeldroid.app import android.content.Context import android.content.Intent @@ -22,13 +22,13 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import androidx.test.rule.GrantPermissionRule import com.google.android.material.tabs.TabLayout -import com.h.pixeldroid.postCreation.photoEdit.PhotoEditActivity -import com.h.pixeldroid.postCreation.photoEdit.ThumbnailAdapter -import com.h.pixeldroid.settings.AboutActivity -import com.h.pixeldroid.testUtility.clearData -import com.h.pixeldroid.testUtility.clickChildViewWithId -import com.h.pixeldroid.testUtility.slowSwipeLeft -import com.h.pixeldroid.testUtility.waitForView +import org.pixeldroid.app.postCreation.photoEdit.PhotoEditActivity +import org.pixeldroid.app.postCreation.photoEdit.ThumbnailAdapter +import org.pixeldroid.app.settings.AboutActivity +import org.pixeldroid.app.testUtility.clearData +import org.pixeldroid.app.testUtility.clickChildViewWithId +import org.pixeldroid.app.testUtility.slowSwipeLeft +import org.pixeldroid.app.testUtility.waitForView import org.hamcrest.CoreMatchers.allOf import org.junit.* import org.junit.Assert.assertTrue @@ -70,7 +70,9 @@ class EditPhotoTest { file.writeBitmap(image) uri = file.toUri() } - val intent = Intent(context, PhotoEditActivity::class.java).putExtra("picture_uri", uri) + val intent = Intent(context, PhotoEditActivity::class.java) + .putExtra(PhotoEditActivity.PICTURE_URI, uri) + .putExtra(PhotoEditActivity.PICTURE_POSITION, 0) activityScenario = ActivityScenario.launch(intent).onActivity{a -> activity = a} diff --git a/app/src/androidTest/java/com/h/pixeldroid/HomeFeedTest.kt b/app/src/androidTest/java/org/pixeldroid/app/HomeFeedTest.kt similarity index 81% rename from app/src/androidTest/java/com/h/pixeldroid/HomeFeedTest.kt rename to app/src/androidTest/java/org/pixeldroid/app/HomeFeedTest.kt index d97d376d..84c9e735 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/HomeFeedTest.kt +++ b/app/src/androidTest/java/org/pixeldroid/app/HomeFeedTest.kt @@ -1,10 +1,12 @@ -package com.h.pixeldroid +package org.pixeldroid.app import android.content.Context import androidx.test.core.app.ActivityScenario import androidx.test.core.app.ApplicationProvider import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions +import androidx.test.espresso.action.ViewActions.openLinkWithText import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition import androidx.test.espresso.contrib.RecyclerViewActions.scrollToPosition @@ -12,17 +14,21 @@ import androidx.test.espresso.matcher.ViewMatchers.* import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.viewpager2.widget.ViewPager2 import com.google.android.material.tabs.TabLayout -import com.h.pixeldroid.utils.db.AppDatabase -import com.h.pixeldroid.posts.StatusViewHolder -import com.h.pixeldroid.testUtility.* -import org.hamcrest.CoreMatchers.not +import org.hamcrest.CoreMatchers.* +import org.pixeldroid.app.utils.db.AppDatabase +import org.pixeldroid.app.posts.StatusViewHolder +import org.pixeldroid.app.testUtility.* +import org.hamcrest.core.IsInstanceOf +import org.hamcrest.core.StringContains.containsString import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test +import org.junit.rules.TestRule import org.junit.rules.Timeout +import org.junit.runner.Description import org.junit.runner.RunWith - +import org.junit.runners.model.Statement @RunWith(AndroidJUnit4::class) class HomeFeedTest { @@ -31,8 +37,9 @@ class HomeFeedTest { private lateinit var db: AppDatabase private lateinit var context: Context - @get:Rule - var globalTimeout: Timeout = Timeout.seconds(100) + @Rule @JvmField + var repeatRule: RepeatRule = RepeatRule() + @Before fun before(){ @@ -47,6 +54,10 @@ class HomeFeedTest { ) db.close() activityScenario = ActivityScenario.launch(MainActivity::class.java) + + waitForView(R.id.username) + onView(withId(R.id.list)).perform(scrollToPosition(0)) + } @After fun after() { @@ -54,6 +65,7 @@ class HomeFeedTest { } @Test + @RepeatTest fun clickingTabOnAlbumShowsNextPhoto() { //Wait for the feed to load waitForView(R.id.postPager) @@ -66,6 +78,40 @@ class HomeFeedTest { } onView(first(withId(R.id.postPager))).check(matches(isDisplayed())) } + + @Test + @RepeatTest + fun tabReClickScrollUp() { + //Wait for the feed to load + waitForView(R.id.postPager) + + onView(withId(R.id.list)).perform(scrollToPosition(4)) + + onView(first(IsInstanceOf.instanceOf(TabLayout.TabView::class.java))).perform(ViewActions.click()) + + + onView(first(withId(R.id.description))).check(matches(withText(containsString("@user2")))); + } + + @Test + @RepeatTest + fun hashtag() { + //Wait for the feed to load + waitForView(R.id.postPager) + + onView(allOf(withClassName(endsWith("RecyclerView")), not(withId(R.id.material_drawer_recycler_view)))) + .perform( + scrollToPosition(3) + ) + + onView(allOf(withText(containsString("randomNoise")))) + .perform(clickClickableSpan("#randomNoise")) + + waitForView(R.id.action_bar, allOf(withText("#randomNoise"), not(withId(R.id.description)))) + + onView(withId(R.id.action_bar)).check(matches(isDisplayed())); + onView(allOf(withText("#randomNoise"), not(withId(R.id.description)))).check(matches(withParent(withId(R.id.action_bar)))); + } /* @Test fun clickingReblogButtonWorks() { @@ -127,6 +173,7 @@ class HomeFeedTest { }*/ @Test + @RepeatTest fun clickingUsernameOpensProfile() { waitForView(R.id.username) @@ -137,6 +184,7 @@ class HomeFeedTest { } @Test + @RepeatTest fun clickingProfilePicOpensProfile() { waitForView(R.id.profilePic) @@ -147,6 +195,7 @@ class HomeFeedTest { } @Test + @RepeatTest fun clickingMentionOpensProfile() { waitForView(R.id.description) @@ -156,13 +205,6 @@ class HomeFeedTest { onView(first(withId(R.id.username))).check(matches(isDisplayed())) } /* - @Test - fun clickingHashTagsWorks() { - onView(withId(R.id.list)).perform( - actionOnItemAtPosition(1, clickChildViewWithId(R.id.description)) - ) - onView(withId(R.id.list)).check(matches(isDisplayed())) - } @Test @@ -217,6 +259,7 @@ class HomeFeedTest { .check(matches(hasDescendant(withId(R.id.comment)))) }*/ + @RepeatTest @Test fun performClickOnSensitiveWarning() { waitForView(R.id.username) @@ -232,11 +275,10 @@ class HomeFeedTest { } @Test + @RepeatTest fun performClickOnSensitiveWarningTabs() { waitForView(R.id.username) - onView(withId(R.id.list)).perform(scrollToPosition(0)) - onView(first(withId(R.id.sensitiveWarning))).check(matches(withEffectiveVisibility(Visibility.VISIBLE))) onView(withId(R.id.list)) diff --git a/app/src/androidTest/java/com/h/pixeldroid/IntentTest.kt b/app/src/androidTest/java/org/pixeldroid/app/IntentTest.kt similarity index 83% rename from app/src/androidTest/java/com/h/pixeldroid/IntentTest.kt rename to app/src/androidTest/java/org/pixeldroid/app/IntentTest.kt index 55696c3f..7b29e396 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/IntentTest.kt +++ b/app/src/androidTest/java/org/pixeldroid/app/IntentTest.kt @@ -1,17 +1,10 @@ -package com.h.pixeldroid +package org.pixeldroid.app import android.content.Context import android.content.Intent -import android.text.SpannableString -import android.text.style.ClickableSpan -import android.view.View -import android.widget.TextView import androidx.test.core.app.ActivityScenario import androidx.test.core.app.ApplicationProvider import androidx.test.espresso.Espresso -import androidx.test.espresso.NoMatchingViewException -import androidx.test.espresso.UiController -import androidx.test.espresso.ViewAction import androidx.test.espresso.action.ViewActions import androidx.test.espresso.assertion.ViewAssertions import androidx.test.espresso.contrib.DrawerActions @@ -23,17 +16,14 @@ import androidx.test.espresso.intent.matcher.IntentMatchers import androidx.test.espresso.matcher.ViewMatchers import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.rule.ActivityTestRule -import com.h.pixeldroid.utils.db.AppDatabase -import com.h.pixeldroid.utils.db.entities.InstanceDatabaseEntity -import com.h.pixeldroid.utils.db.entities.UserDatabaseEntity -import com.h.pixeldroid.posts.StatusViewHolder -import com.h.pixeldroid.utils.api.objects.Account -import com.h.pixeldroid.utils.api.objects.Account.Companion.ACCOUNT_TAG -import com.h.pixeldroid.settings.AboutActivity -import com.h.pixeldroid.testUtility.* +import org.pixeldroid.app.utils.db.AppDatabase +import org.pixeldroid.app.posts.StatusViewHolder +import org.pixeldroid.app.utils.api.objects.Account +import org.pixeldroid.app.utils.api.objects.Account.Companion.ACCOUNT_TAG +import org.pixeldroid.app.settings.AboutActivity +import org.pixeldroid.app.testUtility.* import org.hamcrest.CoreMatchers import org.hamcrest.Matcher -import org.hamcrest.Matchers import org.junit.After import org.junit.Before import org.junit.Rule diff --git a/app/src/androidTest/java/com/h/pixeldroid/LoginActivityOfflineTest.kt b/app/src/androidTest/java/org/pixeldroid/app/LoginActivityOfflineTest.kt similarity index 65% rename from app/src/androidTest/java/com/h/pixeldroid/LoginActivityOfflineTest.kt rename to app/src/androidTest/java/org/pixeldroid/app/LoginActivityOfflineTest.kt index d1ca17c3..324aa9db 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/LoginActivityOfflineTest.kt +++ b/app/src/androidTest/java/org/pixeldroid/app/LoginActivityOfflineTest.kt @@ -1,5 +1,5 @@ -package com.h.pixeldroid -/* +package org.pixeldroid.app + import android.content.Context import androidx.test.core.app.ActivityScenario import androidx.test.core.app.ApplicationProvider @@ -9,33 +9,20 @@ import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation -import androidx.test.uiautomator.UiDevice -import androidx.test.uiautomator.UiSelector -import com.h.pixeldroid.testUtility.clearData -import com.h.pixeldroid.testUtility.initDB -import com.h.pixeldroid.utils.db.AppDatabase -import org.junit.After -import org.junit.Before -import org.junit.Rule -import org.junit.Test +import org.junit.* +import org.pixeldroid.app.testUtility.clearData +import org.pixeldroid.app.testUtility.initDB +import org.pixeldroid.app.utils.db.AppDatabase import org.junit.rules.Timeout import org.junit.runner.RunWith +import org.pixeldroid.app.testUtility.waitForView @RunWith(AndroidJUnit4::class) +@Ignore("Ignore until we can get TestButler to work on CI") class LoginActivityOfflineTest { private lateinit var context: Context - companion object { - fun switchAirplaneMode() { - val device = UiDevice.getInstance(getInstrumentation()) - device.openQuickSettings() - device.findObject(UiSelector().textContains("Airplane")).click() - device.pressHome() - } - } - private lateinit var db: AppDatabase @get:Rule @@ -43,7 +30,8 @@ class LoginActivityOfflineTest { @Before fun before() { - switchAirplaneMode() + //TestButler.setWifiState(false) + //TestButler.setGsmState(false) context = ApplicationProvider.getApplicationContext() db = initDB(context) db.clearAllTables() @@ -52,19 +40,22 @@ class LoginActivityOfflineTest { @Test fun emptyDBandOfflineModeDisplayCorrectMessage() { + waitForView(R.id.login_activity_connection_required) onView(withId(R.id.login_activity_connection_required)).check(matches(isDisplayed())) } @Test fun retryButtonReloadsLoginActivity() { + waitForView(R.id.login_activity_connection_required_button) onView(withId(R.id.login_activity_connection_required_button)).perform(click()) onView(withId(R.id.login_activity_connection_required)).check(matches(isDisplayed())) } @After fun after() { - switchAirplaneMode() + //TestButler.setWifiState(true) + //TestButler.setGsmState(true) db.close() clearData() } -}*/ \ No newline at end of file +} \ No newline at end of file diff --git a/app/src/androidTest/java/com/h/pixeldroid/LoginActivityOnlineTest.kt b/app/src/androidTest/java/org/pixeldroid/app/LoginActivityOnlineTest.kt similarity index 83% rename from app/src/androidTest/java/com/h/pixeldroid/LoginActivityOnlineTest.kt rename to app/src/androidTest/java/org/pixeldroid/app/LoginActivityOnlineTest.kt index dc0a0c73..3bb7dde5 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/LoginActivityOnlineTest.kt +++ b/app/src/androidTest/java/org/pixeldroid/app/LoginActivityOnlineTest.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid +package org.pixeldroid.app import android.content.Context import android.content.Intent @@ -13,22 +13,18 @@ import androidx.test.espresso.action.ViewActions.closeSoftKeyboard import androidx.test.espresso.action.ViewActions.replaceText import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers.hasErrorText -import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.h.pixeldroid.utils.db.AppDatabase -import com.h.pixeldroid.utils.db.entities.InstanceDatabaseEntity -import com.h.pixeldroid.utils.db.entities.UserDatabaseEntity -import com.h.pixeldroid.testUtility.clearData -import com.h.pixeldroid.testUtility.initDB -import com.h.pixeldroid.testUtility.testiTesto -import com.h.pixeldroid.testUtility.testiTestoInstance +import org.pixeldroid.app.utils.db.AppDatabase +import org.pixeldroid.app.testUtility.clearData +import org.pixeldroid.app.testUtility.initDB import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.Timeout import org.junit.runner.RunWith +import org.pixeldroid.app.testUtility.PACKAGE_ID @RunWith(AndroidJUnit4::class) class LoginActivityOnlineTest { @@ -44,7 +40,7 @@ class LoginActivityOnlineTest { fun setup() { context = ApplicationProvider.getApplicationContext() context = ApplicationProvider.getApplicationContext() - pref = context.getSharedPreferences("com.h.pixeldroid.pref", Context.MODE_PRIVATE) + pref = context.getSharedPreferences("${PACKAGE_ID}.pref", Context.MODE_PRIVATE) pref.edit().clear().apply() db = initDB(context) db.clearAllTables() @@ -81,7 +77,7 @@ class LoginActivityOnlineTest { .putString("clientID", "iwndoiuqwnd") .putString("clientSecret", "wlifowed") .apply() - val uri = Uri.parse("oauth2redirect://com.h.pixeldroid?code=sdfdqsf") + val uri = Uri.parse("oauth2redirect://${PACKAGE_ID}?code=sdfdqsf") val intent = Intent(ACTION_VIEW, uri, context, LoginActivity::class.java) ActivityScenario.launch(intent) onView(withId(R.id.editText)).check(matches( @@ -91,7 +87,7 @@ class LoginActivityOnlineTest { @Test fun incompleteIntentReturnInfoFailsTest() { - val uri = Uri.parse("oauth2redirect://com.h.pixeldroid?code=") + val uri = Uri.parse("oauth2redirect://${PACKAGE_ID}?code=") val intent = Intent(ACTION_VIEW, uri, context, LoginActivity::class.java) ActivityScenario.launch(intent) onView(withId(R.id.editText)).check(matches( @@ -117,7 +113,7 @@ class LoginActivityOnlineTest { .putString("clientID", testiTesto.clientId) .putString("clientSecret", testiTesto.clientSecret) .apply() - val uri = Uri.parse("oauth2redirect://com.h.pixeldroid?code=$testiTesto.") + val uri = Uri.parse("oauth2redirect://org.pixeldroid.app?code=$testiTesto.") val intent = Intent(ACTION_VIEW, uri, context, LoginActivity::class.java) ActivityScenario.launch(intent) Thread.sleep(1000) diff --git a/app/src/androidTest/java/com/h/pixeldroid/LoginCheckIntent.kt b/app/src/androidTest/java/org/pixeldroid/app/LoginCheckIntent.kt similarity index 88% rename from app/src/androidTest/java/com/h/pixeldroid/LoginCheckIntent.kt rename to app/src/androidTest/java/org/pixeldroid/app/LoginCheckIntent.kt index 43a183bf..571b77ac 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/LoginCheckIntent.kt +++ b/app/src/androidTest/java/org/pixeldroid/app/LoginCheckIntent.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid +package org.pixeldroid.app import android.content.Intent import android.content.Intent.ACTION_VIEW @@ -15,12 +15,9 @@ import androidx.test.espresso.intent.matcher.IntentMatchers.hasDataString import androidx.test.espresso.matcher.RootMatchers.isDialog import androidx.test.espresso.matcher.ViewMatchers.* import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation -import androidx.test.rule.ActivityTestRule -import androidx.test.uiautomator.UiDevice -import com.h.pixeldroid.BuildConfig.INSTANCE_URI -import com.h.pixeldroid.testUtility.clearData -import com.h.pixeldroid.testUtility.waitForView +import org.pixeldroid.app.BuildConfig.INSTANCE_URI +import org.pixeldroid.app.testUtility.clearData +import org.pixeldroid.app.testUtility.waitForView import org.hamcrest.CoreMatchers.allOf import org.hamcrest.CoreMatchers.containsString import org.hamcrest.Matcher diff --git a/app/src/androidTest/java/com/h/pixeldroid/MockedServerTest.kt b/app/src/androidTest/java/org/pixeldroid/app/MockedServerTest.kt similarity index 98% rename from app/src/androidTest/java/com/h/pixeldroid/MockedServerTest.kt rename to app/src/androidTest/java/org/pixeldroid/app/MockedServerTest.kt index 68f548da..663e5e9c 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/MockedServerTest.kt +++ b/app/src/androidTest/java/org/pixeldroid/app/MockedServerTest.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid +package org.pixeldroid.app import android.content.Context @@ -11,8 +11,8 @@ import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers.* import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.android.material.tabs.TabLayout -import com.h.pixeldroid.testUtility.* -import com.h.pixeldroid.utils.db.AppDatabase +import org.pixeldroid.app.testUtility.* +import org.pixeldroid.app.utils.db.AppDatabase import org.junit.After import org.junit.Before import org.junit.Test diff --git a/app/src/androidTest/java/com/h/pixeldroid/PostCreationActivityTest.kt b/app/src/androidTest/java/org/pixeldroid/app/PostCreationActivityTest.kt similarity index 54% rename from app/src/androidTest/java/com/h/pixeldroid/PostCreationActivityTest.kt rename to app/src/androidTest/java/org/pixeldroid/app/PostCreationActivityTest.kt index c3f33937..0c11b73d 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/PostCreationActivityTest.kt +++ b/app/src/androidTest/java/org/pixeldroid/app/PostCreationActivityTest.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid +package org.pixeldroid.app import android.Manifest import android.content.ClipData @@ -7,26 +7,21 @@ import android.content.Intent import android.graphics.Bitmap import android.graphics.Color import android.net.Uri -import android.util.Log -import android.view.View.VISIBLE import androidx.core.net.toUri -import androidx.core.os.bundleOf import androidx.test.core.app.ActivityScenario import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.action.ViewActions.typeText +import androidx.test.espresso.assertion.ViewAssertions.doesNotExist import androidx.test.espresso.assertion.ViewAssertions.matches -import androidx.test.espresso.contrib.RecyclerViewActions -import androidx.test.espresso.matcher.ViewMatchers.isDisplayed -import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.* import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import androidx.test.rule.GrantPermissionRule -import com.h.pixeldroid.postCreation.PostCreationActivity -import com.h.pixeldroid.postCreation.photoEdit.ThumbnailAdapter -import com.h.pixeldroid.settings.AboutActivity -import com.h.pixeldroid.testUtility.* -import com.h.pixeldroid.utils.db.AppDatabase -import org.hamcrest.CoreMatchers.not +import org.pixeldroid.app.postCreation.PostCreationActivity +import org.pixeldroid.app.settings.AboutActivity +import org.pixeldroid.app.testUtility.* +import org.pixeldroid.app.utils.db.AppDatabase import org.junit.* import org.junit.rules.Timeout import org.junit.runner.RunWith @@ -44,7 +39,8 @@ class PostCreationActivityTest { val globalTimeout: Timeout = Timeout.seconds(30) @get:Rule - val mRuntimePermissionRule: GrantPermissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE) + val mRuntimePermissionRule: GrantPermissionRule = + GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE) private fun File.writeBitmap(bitmap: Bitmap) { outputStream().use { out -> @@ -112,32 +108,101 @@ class PostCreationActivityTest { // should send on main activity onView(withId(R.id.retry_upload_button)).check(matches(not(isDisplayed()))) } +*/ + /** + * Makes sure the [org.pixeldroid.app.postCreation.photoEdit.PhotoEditActivity] is launched + * when the edit button is pressed + */ @Test fun editImage() { - Thread.sleep(1000) + waitForView(R.id.postTextInputLayout) - onView(withId(R.id.image_grid)).perform( - RecyclerViewActions.actionOnItemAtPosition( - 0, - CustomMatchers.clickChildViewWithId(R.id.galleryImage) - ) - ) - Thread.sleep(1000) + onView(withId(R.id.editPhotoButton)).perform(click()) - onView(withId(R.id.recycler_view)) - .perform( - RecyclerViewActions.actionOnItemAtPosition( - 2, - CustomMatchers.clickChildViewWithId(R.id.thumbnail) - ) - ) - Thread.sleep(1000) - onView(withId(R.id.action_save)).perform(click()) - Thread.sleep(1000) - onView(withId(R.id.carousel)).check(matches(isDisplayed())) + waitForView(R.id.cropImageButton) } + /** + * Switch from carousel to grid and back + */ + @Test + fun carouselSwitch() { + waitForView(R.id.postTextInputLayout) + + onView(withId(R.id.switchToGridButton)).perform(click()) + + waitForView(R.id.galleryImage) + + onView(withId(R.id.switchToCarouselButton)).perform(click()) + + waitForView(R.id.btn_previous) + } + + /** + * Delete images and check if it worked + */ + @Test + fun deleteImages() { + waitForView(R.id.postTextInputLayout) + + onView(withId(R.id.removePhotoButton)).perform(click()).perform(click()) + + onView(withId(R.id.switchToGridButton)).perform(click()) + + onView(withId(R.id.galleryImage)).check(doesNotExist()) + onView(withId(R.id.addPhotoSquare)).check(matches(isDisplayed())) + } + + /** + * Type media description and check it's saved + */ + @Test + fun mediaDescription() { + waitForView(R.id.postTextInputLayout) + + + fun typeDescription(text: String) { + onView(withId(R.id.tv_caption)).perform(click()) + + waitForView(R.id.editTextMediaDescription) + + onView(withId(R.id.editTextMediaDescription)).perform(typeText(text)) + onView(withId(R.id.imageDescriptionButton)).perform(click()) + + onView(withId(R.id.tv_caption)).check(matches(withText(text))) + } + + val typedText1 = "Testi testo description" + typeDescription(typedText1) + + onView(withId(R.id.btn_next)).perform(click()) + + val typedText2 = "Description 2" + typeDescription(typedText2) + + onView(withId(R.id.btn_previous)).perform(click()) + + onView(withId(R.id.tv_caption)).check(matches(withText(typedText1))) + + onView(withId(R.id.btn_next)).perform(click()) + + onView(withId(R.id.tv_caption)).check(matches(withText(typedText2))) + } + + /** + * Makes sure the [org.pixeldroid.app.postCreation.camera.CameraActivity] is launched + * when the add image button is pressed + */ + @Test + fun addImage() { + waitForView(R.id.postTextInputLayout) + + onView(withId(R.id.addPhotoButton)).perform(click()) + + waitForView(R.id.camera_activity_fragment) + } +/* @Test fun cancelEdit() { onView(withId(R.id.image_grid)).perform( diff --git a/app/src/androidTest/java/com/h/pixeldroid/PostCreationFragmentTest.kt b/app/src/androidTest/java/org/pixeldroid/app/PostCreationFragmentTest.kt similarity index 96% rename from app/src/androidTest/java/com/h/pixeldroid/PostCreationFragmentTest.kt rename to app/src/androidTest/java/org/pixeldroid/app/PostCreationFragmentTest.kt index f5317e69..71788bbd 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/PostCreationFragmentTest.kt +++ b/app/src/androidTest/java/org/pixeldroid/app/PostCreationFragmentTest.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid +package org.pixeldroid.app import android.content.Context import android.content.Intent @@ -17,8 +17,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import androidx.test.rule.GrantPermissionRule import com.google.android.material.tabs.TabLayout -import com.h.pixeldroid.testUtility.* -import com.h.pixeldroid.utils.db.AppDatabase +import org.pixeldroid.app.testUtility.* +import org.pixeldroid.app.utils.db.AppDatabase import org.hamcrest.Matcher import org.junit.After import org.junit.Before diff --git a/app/src/androidTest/java/com/h/pixeldroid/PostTest.kt b/app/src/androidTest/java/org/pixeldroid/app/PostTest.kt similarity index 95% rename from app/src/androidTest/java/com/h/pixeldroid/PostTest.kt rename to app/src/androidTest/java/org/pixeldroid/app/PostTest.kt index 7426a9c0..5e833694 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/PostTest.kt +++ b/app/src/androidTest/java/org/pixeldroid/app/PostTest.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid +package org.pixeldroid.app import android.content.Context import android.content.Intent @@ -13,16 +13,14 @@ import androidx.test.espresso.matcher.ViewMatchers.* import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation -import com.h.pixeldroid.BuildConfig.INSTANCE_URI -import com.h.pixeldroid.posts.PostActivity -import com.h.pixeldroid.utils.db.AppDatabase -import com.h.pixeldroid.utils.db.entities.InstanceDatabaseEntity -import com.h.pixeldroid.utils.db.entities.UserDatabaseEntity -import com.h.pixeldroid.utils.api.objects.* -import com.h.pixeldroid.testUtility.clearData -import com.h.pixeldroid.testUtility.initDB -import com.h.pixeldroid.testUtility.testiTesto -import com.h.pixeldroid.testUtility.testiTestoInstance +import org.pixeldroid.app.BuildConfig.INSTANCE_URI +import org.pixeldroid.app.posts.PostActivity +import org.pixeldroid.app.utils.db.AppDatabase +import org.pixeldroid.app.utils.api.objects.* +import org.pixeldroid.app.testUtility.clearData +import org.pixeldroid.app.testUtility.initDB +import org.pixeldroid.app.testUtility.testiTesto +import org.pixeldroid.app.testUtility.testiTestoInstance import org.hamcrest.CoreMatchers.anyOf import org.hamcrest.Matcher import org.junit.* diff --git a/app/src/androidTest/java/com/h/pixeldroid/ProfileTest.kt b/app/src/androidTest/java/org/pixeldroid/app/ProfileTest.kt similarity index 88% rename from app/src/androidTest/java/com/h/pixeldroid/ProfileTest.kt rename to app/src/androidTest/java/org/pixeldroid/app/ProfileTest.kt index a1acbf45..778a3946 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/ProfileTest.kt +++ b/app/src/androidTest/java/org/pixeldroid/app/ProfileTest.kt @@ -1,29 +1,24 @@ -package com.h.pixeldroid +package org.pixeldroid.app import android.content.Context import android.content.Intent import androidx.test.core.app.ActivityScenario import androidx.test.core.app.ApplicationProvider -import androidx.test.espresso.Espresso import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions import androidx.test.espresso.action.ViewActions.swipeDown import androidx.test.espresso.assertion.ViewAssertions -import androidx.test.espresso.contrib.RecyclerViewActions import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.h.pixeldroid.postCreation.PostCreationActivity -import com.h.pixeldroid.profile.ProfileActivity -import com.h.pixeldroid.testUtility.* -import com.h.pixeldroid.utils.api.objects.Account -import com.h.pixeldroid.utils.db.AppDatabase -import okhttp3.internal.wait +import org.pixeldroid.app.profile.ProfileActivity +import org.pixeldroid.app.testUtility.* +import org.pixeldroid.app.utils.api.objects.Account +import org.pixeldroid.app.utils.db.AppDatabase import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import java.io.Serializable @RunWith(AndroidJUnit4::class) class ProfileTest { diff --git a/app/src/androidTest/java/com/h/pixeldroid/testUtility/CustomMatchers.kt b/app/src/androidTest/java/org/pixeldroid/app/testUtility/CustomMatchers.kt similarity index 75% rename from app/src/androidTest/java/com/h/pixeldroid/testUtility/CustomMatchers.kt rename to app/src/androidTest/java/org/pixeldroid/app/testUtility/CustomMatchers.kt index de1ce3f2..5b336b5f 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/testUtility/CustomMatchers.kt +++ b/app/src/androidTest/java/org/pixeldroid/app/testUtility/CustomMatchers.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.testUtility +package org.pixeldroid.app.testUtility import android.text.SpannableString import android.text.style.ClickableSpan @@ -8,6 +8,7 @@ import android.widget.TextView import androidx.appcompat.widget.SearchView import androidx.recyclerview.widget.RecyclerView import androidx.test.espresso.* +import androidx.test.espresso.NoMatchingViewException import androidx.test.espresso.action.* import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.BoundedMatcher @@ -15,15 +16,43 @@ import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers.* import androidx.test.espresso.util.HumanReadables import androidx.test.espresso.util.TreeIterables -import com.h.pixeldroid.R import org.hamcrest.BaseMatcher import org.hamcrest.CoreMatchers.allOf import org.hamcrest.Description import org.hamcrest.Matcher import org.hamcrest.Matchers +import org.junit.rules.TestRule +import org.junit.runners.model.Statement +import org.pixeldroid.app.R import java.util.concurrent.TimeoutException +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.FUNCTION, AnnotationTarget.ANNOTATION_CLASS) +annotation class RepeatTest(val value: Int = 1) + +class RepeatRule : TestRule { + + private class RepeatStatement(private val statement: Statement, private val repeat: Int) : Statement() { + @Throws(Throwable::class) + override fun evaluate() { + for (i in 0 until repeat) { + statement.evaluate() + } + } + } + + override fun apply(statement: Statement, description: org.junit.runner.Description): Statement { + var result = statement + val repeat = description.getAnnotation(RepeatTest::class.java) + if (repeat != null) { + val times = repeat.value + result = RepeatStatement(statement, times) + } + return result + } +} + fun ViewInteraction.isDisplayed(): Boolean { return try { check(matches(ViewMatchers.isDisplayed())) @@ -38,15 +67,15 @@ fun ViewInteraction.isDisplayed(): Boolean { * Doesn't work if the root changes (since it operates on the root!) * @param viewId The id of the view to wait for. */ -fun waitForView(viewId: Int) { - Espresso.onView(isRoot()).perform(waitForViewViewAction(viewId)) +fun waitForView(viewId: Int, viewMatcher: Matcher = withId(viewId)) { + Espresso.onView(isRoot()).perform(waitForViewViewAction(viewId, viewMatcher)) } /** * This ViewAction tells espresso to wait till a certain view is found in the view hierarchy. * @param viewId The id of the view to wait for. */ -private fun waitForViewViewAction(viewId: Int): ViewAction { +private fun waitForViewViewAction(viewId: Int, viewMatcher: Matcher): ViewAction { // The maximum time which espresso will wait for the view to show up (in milliseconds) val timeOut = 5000 return object : ViewAction { @@ -62,7 +91,6 @@ private fun waitForViewViewAction(viewId: Int): ViewAction { uiController.loopMainThreadUntilIdle() val startTime = System.currentTimeMillis() val endTime = startTime + timeOut - val viewMatcher = withId(viewId) do { // Iterate through all views on the screen and see if the view we are looking for is there already @@ -75,7 +103,7 @@ private fun waitForViewViewAction(viewId: Int): ViewAction { // Loops the main thread for a specified period of time. // Control may not return immediately, instead it'll return after the provided delay has passed and the queue is in an idle state again. uiController.loopMainThreadForAtLeast(100) - } while (System.currentTimeMillis() < endTime) // in case of a timeout we throw an exception -> test fails + } while (System.currentTimeMillis() < endTime) // in case of a timeout we throw an exception - test fails throw PerformException.Builder() .withCause(TimeoutException()) .withActionDescription(this.description) @@ -271,6 +299,54 @@ fun clickChildViewWithId(id: Int) = object : ViewAction { } } +fun clickClickableSpan(textToClick: CharSequence): ViewAction? { + return object : ViewAction { + override fun getConstraints(): Matcher { + return Matchers.instanceOf(TextView::class.java) + } + + override fun getDescription(): String { + return "clicking on a ClickableSpan" + } + + override fun perform(uiController: UiController?, view: View) { + val textView = view as TextView + val spannableString = textView.text as SpannableString + if (spannableString.isEmpty()) { + // TextView is empty, nothing to do + throw NoMatchingViewException.Builder() + .includeViewHierarchy(true) + .withRootView(textView) + .build() + } + + // Get the links inside the TextView and check if we find textToClick + val spans = spannableString.getSpans( + 0, spannableString.length, + ClickableSpan::class.java + ) + if (spans.isNotEmpty()) { + var spanCandidate: ClickableSpan? + for (span in spans) { + spanCandidate = span + val start = spannableString.getSpanStart(spanCandidate) + val end = spannableString.getSpanEnd(spanCandidate) + val sequence = spannableString.subSequence(start, end) + if (textToClick.toString() == sequence.toString()) { + span.onClick(textView) + return + } + } + } + throw NoMatchingViewException.Builder() + .includeViewHierarchy(true) + .withRootView(textView) + .build() + } + } +} + + fun typeTextInViewWithId(id: Int, text: String) = object : ViewAction { override fun getConstraints() = null diff --git a/app/src/androidTest/java/com/h/pixeldroid/testUtility/DbHelpers.kt b/app/src/androidTest/java/org/pixeldroid/app/testUtility/DbHelpers.kt similarity index 79% rename from app/src/androidTest/java/com/h/pixeldroid/testUtility/DbHelpers.kt rename to app/src/androidTest/java/org/pixeldroid/app/testUtility/DbHelpers.kt index 57d84765..80cee48a 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/testUtility/DbHelpers.kt +++ b/app/src/androidTest/java/org/pixeldroid/app/testUtility/DbHelpers.kt @@ -1,8 +1,8 @@ -package com.h.pixeldroid.testUtility +package org.pixeldroid.app.testUtility import android.content.Context import androidx.room.Room -import com.h.pixeldroid.utils.db.AppDatabase +import org.pixeldroid.app.utils.db.AppDatabase import org.ligi.tracedroid.TraceDroid diff --git a/app/src/androidTest/java/org/pixeldroid/app/testUtility/TestRunner.kt b/app/src/androidTest/java/org/pixeldroid/app/testUtility/TestRunner.kt new file mode 100644 index 00000000..a603d2bc --- /dev/null +++ b/app/src/androidTest/java/org/pixeldroid/app/testUtility/TestRunner.kt @@ -0,0 +1,20 @@ +package org.pixeldroid.app.testUtility +/* +import android.os.Bundle +import androidx.test.runner.AndroidJUnitRunner +import com.linkedin.android.testbutler.TestButler + + +class TestRunner: AndroidJUnitRunner() { + override fun onStart() { + TestButler.setup(targetContext) + super.onStart() + } + + override fun finish(resultCode: Int, results: Bundle) { + TestButler.teardown(targetContext) + super.finish(resultCode, results) + } +} + + */ \ No newline at end of file diff --git a/app/src/androidTest/java/com/h/pixeldroid/testUtility/Values.kt b/app/src/androidTest/java/org/pixeldroid/app/testUtility/Values.kt similarity index 72% rename from app/src/androidTest/java/com/h/pixeldroid/testUtility/Values.kt rename to app/src/androidTest/java/org/pixeldroid/app/testUtility/Values.kt index c048b060..04f8408c 100644 --- a/app/src/androidTest/java/com/h/pixeldroid/testUtility/Values.kt +++ b/app/src/androidTest/java/org/pixeldroid/app/testUtility/Values.kt @@ -1,8 +1,12 @@ -package com.h.pixeldroid.testUtility +package org.pixeldroid.app.testUtility + +import org.pixeldroid.app.BuildConfig.* +import org.pixeldroid.app.utils.db.entities.InstanceDatabaseEntity +import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity + + +const val PACKAGE_ID = APPLICATION_ID -import com.h.pixeldroid.BuildConfig.* -import com.h.pixeldroid.utils.db.entities.InstanceDatabaseEntity -import com.h.pixeldroid.utils.db.entities.UserDatabaseEntity val testiTestoInstance = InstanceDatabaseEntity( uri = INSTANCE_URI, diff --git a/app/src/debug/res/drawable-v24/ic_launcher_foreground.xml b/app/src/debug/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 00000000..b382f73c --- /dev/null +++ b/app/src/debug/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/debug/res/drawable/ic_launcher_background.xml b/app/src/debug/res/drawable/ic_launcher_background.xml new file mode 100644 index 00000000..ca3826a4 --- /dev/null +++ b/app/src/debug/res/drawable/ic_launcher_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 00000000..bbd3e021 --- /dev/null +++ b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/debug/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 00000000..bbd3e021 --- /dev/null +++ b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e02204f9..5974d161 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ + package="org.pixeldroid.app"> @@ -23,7 +23,7 @@ android:supportsRtl="true" android:theme="@style/AppTheme" tools:replace="android:allowBackup"> - + + tools:ignore="LockedOrientationActivity" > + + + + + + + + + + + + + android:value="org.pixeldroid.app.searchDiscover.SearchActivity" />
-

kotlin-android-extensions-runtime

-

Copyright © JetBrains s.r.o. and contributors. All rights reserved.

-

https://kotlinlang.org/

+

startup-runtime

+

Copyright © Google Inc. All rights reserved.

+

https://developer.android.com/jetpack/androidx/releases/startup#1.0.0

diff --git a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/FeedViewModel.kt b/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/FeedViewModel.kt deleted file mode 100644 index 4111b7e9..00000000 --- a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/FeedViewModel.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.h.pixeldroid.posts.feeds.uncachedFeeds - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import androidx.paging.* -import com.h.pixeldroid.utils.api.objects.FeedContent -import kotlinx.coroutines.flow.Flow - -/** - * ViewModel for the uncached feeds. - * The ViewModel works with the different [UncachedContentRepository]s to get the data. - */ -class FeedViewModel(private val repository: UncachedContentRepository) : ViewModel() { - - private var currentResult: Flow>? = null - - fun flow(): Flow> { - val lastResult = currentResult - if (lastResult != null) { - return lastResult - } - val newResult: Flow> = repository.getStream() - .cachedIn(viewModelScope) - currentResult = newResult - return newResult - } -} - -/** - * Common interface for the different uncached feeds - */ -interface UncachedContentRepository{ - fun getStream(): Flow> -} \ No newline at end of file diff --git a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/search/SearchPostsFragment.kt b/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/search/SearchPostsFragment.kt deleted file mode 100644 index bcb7c69b..00000000 --- a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/search/SearchPostsFragment.kt +++ /dev/null @@ -1,88 +0,0 @@ -package com.h.pixeldroid.posts.feeds.uncachedFeeds.search - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.lifecycleScope -import androidx.paging.ExperimentalPagingApi -import androidx.paging.PagingDataAdapter -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.RecyclerView -import com.h.pixeldroid.R -import com.h.pixeldroid.posts.StatusViewHolder -import com.h.pixeldroid.posts.feeds.uncachedFeeds.* -import com.h.pixeldroid.utils.api.objects.Results -import com.h.pixeldroid.utils.api.objects.Status -import com.h.pixeldroid.utils.displayDimensionsInPx - -/** - * Fragment to show a list of [Status]es, as a result of a search. - */ -class SearchPostsFragment : UncachedFeedFragment() { - - private lateinit var query: String - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - adapter = PostsAdapter(requireContext().displayDimensionsInPx()) - - query = arguments?.getSerializable("searchFeed") as String - - } - - @ExperimentalPagingApi - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - val view = super.onCreateView(inflater, container, savedInstanceState) - - // get the view model - @Suppress("UNCHECKED_CAST") - viewModel = ViewModelProvider(this, ViewModelFactory( - SearchContentRepository( - apiHolder.setDomainToCurrentUser(db), - Results.SearchType.statuses, - db.userDao().getActiveUser()!!.accessToken, - query - ) - ) - ) - .get(FeedViewModel::class.java) as FeedViewModel - - launch() - initSearch() - - return view - } - - inner class PostsAdapter(private val displayDimensionsInPx: Pair) : PagingDataAdapter( - object : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: Status, newItem: Status): Boolean { - return oldItem.id == newItem.id - } - - override fun areContentsTheSame(oldItem: Status, newItem: Status): Boolean = - oldItem.id == newItem.id - } - ) { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { - return StatusViewHolder.create(parent) - } - - override fun getItemViewType(position: Int): Int { - return R.layout.post_fragment - } - - override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { - val uiModel = getItem(position) as Status - uiModel.let { - (holder as StatusViewHolder).bind(it, apiHolder.setDomainToCurrentUser(db), db, lifecycleScope, displayDimensionsInPx) - } - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Error.kt b/app/src/main/java/com/h/pixeldroid/utils/api/objects/Error.kt deleted file mode 100644 index 7a2d5be9..00000000 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Error.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.h.pixeldroid.utils.api.objects - -data class Error( - val error: String? -) \ No newline at end of file diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Relationship.kt b/app/src/main/java/com/h/pixeldroid/utils/api/objects/Relationship.kt deleted file mode 100644 index 82e4f951..00000000 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Relationship.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.h.pixeldroid.utils.api.objects - -import java.io.Serializable - -data class Relationship( - // Required atributes - val id: String, - val following: Boolean, - val requested: Boolean, - val endorsed: Boolean, - val followed_by: Boolean, - val muting: Boolean, - val muting_notifications: Boolean, - val showing_reblogs: Boolean, - val blocking: Boolean, - val domain_blocking: Boolean, - val blocked_by: Boolean -) : Serializable diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Tag.kt b/app/src/main/java/com/h/pixeldroid/utils/api/objects/Tag.kt deleted file mode 100644 index 1dcc8c9a..00000000 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Tag.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.h.pixeldroid.utils.api.objects - -import java.io.Serializable - -data class Tag( - //Base attributes - val name: String, - val url: String, - //Optional attributes - val history: List? = emptyList()) : Serializable, FeedContent { - //needed to be a FeedContent, this inheritance is a bit fickle. Do not use. - override val id: String - get() = "tag" -} - diff --git a/app/src/main/java/com/h/pixeldroid/LoginActivity.kt b/app/src/main/java/org/pixeldroid/app/LoginActivity.kt similarity index 91% rename from app/src/main/java/com/h/pixeldroid/LoginActivity.kt rename to app/src/main/java/org/pixeldroid/app/LoginActivity.kt index fde97693..05f5042c 100644 --- a/app/src/main/java/com/h/pixeldroid/LoginActivity.kt +++ b/app/src/main/java/org/pixeldroid/app/LoginActivity.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid +package org.pixeldroid.app import android.app.AlertDialog import android.content.Context @@ -9,12 +9,12 @@ import android.os.Bundle import android.view.View import android.view.inputmethod.InputMethodManager import androidx.lifecycle.lifecycleScope -import com.h.pixeldroid.databinding.ActivityLoginBinding -import com.h.pixeldroid.utils.* -import com.h.pixeldroid.utils.api.PixelfedAPI -import com.h.pixeldroid.utils.api.objects.* -import com.h.pixeldroid.utils.db.addUser -import com.h.pixeldroid.utils.db.storeInstance +import org.pixeldroid.app.databinding.ActivityLoginBinding +import org.pixeldroid.app.utils.* +import org.pixeldroid.app.utils.api.PixelfedAPI +import org.pixeldroid.app.utils.api.objects.* +import org.pixeldroid.app.utils.db.addUser +import org.pixeldroid.app.utils.db.storeInstance import kotlinx.coroutines.* import retrofit2.HttpException import java.io.IOException @@ -25,14 +25,13 @@ Overview of the flow of the login process: (boxes are requests done in parallel, since they do not depend on each other) _________________________________ -|[PixelfedAPI.registerApplicationAsync]| +|[PixelfedAPI.registerApplication]| |[PixelfedAPI.wellKnownNodeInfo] | - ̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅ +----> [PixelfedAPI.nodeInfoSchema] - +----> [promptOAuth] - +---->____________________________ - |[PixelfedAPI.instance] | - |[PixelfedAPI.obtainToken] | - ̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅ +----> [PixelfedAPI.verifyCredentials] + ̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅ ++----> [PixelfedAPI.nodeInfoSchema] (and then [PixelfedAPI.instance] if needed) ++----> [promptOAuth] ++----> [PixelfedAPI.obtainToken] ++----> [PixelfedAPI.verifyCredentials] */ @@ -311,7 +310,7 @@ class LoginActivity : BaseActivity() { clientId = clientId, clientSecret = clientSecret ) - apiHolder.setDomainToCurrentUser(db) + apiHolder.setToCurrentUser() val intent = Intent(this@LoginActivity, MainActivity::class.java) intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK startActivity(intent) diff --git a/app/src/main/java/com/h/pixeldroid/MainActivity.kt b/app/src/main/java/org/pixeldroid/app/MainActivity.kt similarity index 74% rename from app/src/main/java/com/h/pixeldroid/MainActivity.kt rename to app/src/main/java/org/pixeldroid/app/MainActivity.kt index fb2b74dc..1df075f7 100644 --- a/app/src/main/java/com/h/pixeldroid/MainActivity.kt +++ b/app/src/main/java/org/pixeldroid/app/MainActivity.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid +package org.pixeldroid.app import android.content.Context import android.content.Intent @@ -14,22 +14,12 @@ import androidx.core.view.GravityCompat import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import androidx.paging.ExperimentalPagingApi +import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.adapter.FragmentStateAdapter +import androidx.viewpager2.widget.ViewPager2 import com.bumptech.glide.Glide +import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayoutMediator -import com.h.pixeldroid.databinding.ActivityMainBinding -import com.h.pixeldroid.postCreation.camera.CameraFragment -import com.h.pixeldroid.posts.feeds.cachedFeeds.notifications.NotificationsFragment -import com.h.pixeldroid.posts.feeds.cachedFeeds.postFeeds.PostFeedFragment -import com.h.pixeldroid.profile.ProfileActivity -import com.h.pixeldroid.searchDiscover.SearchDiscoverFragment -import com.h.pixeldroid.settings.SettingsActivity -import com.h.pixeldroid.utils.BaseActivity -import com.h.pixeldroid.utils.db.addUser -import com.h.pixeldroid.utils.db.entities.HomeStatusDatabaseEntity -import com.h.pixeldroid.utils.db.entities.PublicFeedStatusDatabaseEntity -import com.h.pixeldroid.utils.db.entities.UserDatabaseEntity -import com.h.pixeldroid.utils.hasInternet import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial import com.mikepenz.materialdrawer.iconics.iconicsIcon import com.mikepenz.materialdrawer.model.PrimaryDrawerItem @@ -40,9 +30,25 @@ import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader import com.mikepenz.materialdrawer.util.DrawerImageLoader import com.mikepenz.materialdrawer.widget.AccountHeaderView import org.ligi.tracedroid.sending.sendTraceDroidStackTracesIfExist +import org.pixeldroid.app.databinding.ActivityMainBinding +import org.pixeldroid.app.postCreation.camera.CameraFragment +import org.pixeldroid.app.posts.NestedScrollableHost +import org.pixeldroid.app.posts.feeds.cachedFeeds.CachedFeedFragment +import org.pixeldroid.app.posts.feeds.cachedFeeds.notifications.NotificationsFragment +import org.pixeldroid.app.posts.feeds.cachedFeeds.postFeeds.PostFeedFragment +import org.pixeldroid.app.profile.ProfileActivity +import org.pixeldroid.app.searchDiscover.SearchDiscoverFragment +import org.pixeldroid.app.settings.SettingsActivity +import org.pixeldroid.app.utils.BaseActivity +import org.pixeldroid.app.utils.db.addUser +import org.pixeldroid.app.utils.db.entities.HomeStatusDatabaseEntity +import org.pixeldroid.app.utils.db.entities.PublicFeedStatusDatabaseEntity +import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity +import org.pixeldroid.app.utils.hasInternet import retrofit2.HttpException import java.io.IOException + class MainActivity : BaseActivity() { private lateinit var header: AccountHeaderView @@ -72,23 +78,22 @@ class MainActivity : BaseActivity() { sendTraceDroidStackTracesIfExist("contact@pixeldroid.org", this) setupDrawer() - val tabs: List<() -> Fragment> = listOf( - { - PostFeedFragment() - .apply { - arguments = Bundle().apply { putBoolean("home", true) } - } - }, - { SearchDiscoverFragment() }, - { CameraFragment() }, - { NotificationsFragment() }, - { - PostFeedFragment() - .apply { - arguments = Bundle().apply { putBoolean("home", false) } - } - } + { + PostFeedFragment() + .apply { + arguments = Bundle().apply { putBoolean("home", true) } + } + }, + { SearchDiscoverFragment() }, + { CameraFragment() }, + { NotificationsFragment() }, + { + PostFeedFragment() + .apply { + arguments = Bundle().apply { putBoolean("home", false) } + } + } ) setupTabs(tabs) } @@ -177,7 +182,7 @@ class MainActivity : BaseActivity() { } else { val newActive = remainingUsers.first() db.userDao().activateUser(newActive.user_id) - apiHolder.setDomainToCurrentUser(db) + apiHolder.setToCurrentUser() //relaunch the app launchActivity(MainActivity(), firstTime = true) } @@ -185,16 +190,17 @@ class MainActivity : BaseActivity() { } private fun getUpdatedAccount() { if (hasInternet(applicationContext)) { - val domain = user?.instance_uri.orEmpty() - val accessToken = user?.accessToken.orEmpty() - val refreshToken = user?.refreshToken - val clientId = user?.clientId.orEmpty() - val clientSecret = user?.clientSecret.orEmpty() - val api = apiHolder.api ?: apiHolder.setDomainToCurrentUser(db) lifecycleScope.launchWhenCreated { try { - val account = api.verifyCredentials("Bearer $accessToken") + val domain = user?.instance_uri.orEmpty() + val accessToken = user?.accessToken.orEmpty() + val refreshToken = user?.refreshToken + val clientId = user?.clientId.orEmpty() + val clientSecret = user?.clientSecret.orEmpty() + val api = apiHolder.api ?: apiHolder.setToCurrentUser() + + val account = api.verifyCredentials() addUser(db, account, domain, accessToken = accessToken, refreshToken = refreshToken, clientId = clientId, clientSecret = clientSecret) fillDrawerAccountInfo(account.id!!) } catch (exception: IOException) { @@ -220,7 +226,7 @@ class MainActivity : BaseActivity() { db.userDao().deActivateActiveUsers() db.userDao().activateUser(profile.identifier.toString()) - apiHolder.setDomainToCurrentUser(db) + apiHolder.setToCurrentUser() val intent = Intent(this, MainActivity::class.java) intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK startActivity(intent) @@ -268,8 +274,22 @@ class MainActivity : BaseActivity() { header.setActiveProfile(account.toLong()) } + /** + * Use reflection to make it a bit harder to swipe between tabs + */ + private fun ViewPager2.reduceDragSensitivity() { + val recyclerViewField = ViewPager2::class.java.getDeclaredField("mRecyclerView") + recyclerViewField.isAccessible = true + val recyclerView = recyclerViewField.get(this) as RecyclerView + + val touchSlopField = RecyclerView::class.java.getDeclaredField("mTouchSlop") + touchSlopField.isAccessible = true + val touchSlop = touchSlopField.get(recyclerView) as Int + touchSlopField.set(recyclerView, touchSlop*NestedScrollableHost.touchSlopModifier) + } private fun setupTabs(tab_array: List<() -> Fragment>){ + binding.viewPager.reduceDragSensitivity() binding.viewPager.adapter = object : FragmentStateAdapter(this) { override fun createFragment(position: Int): Fragment { return tab_array[position]() @@ -279,6 +299,20 @@ class MainActivity : BaseActivity() { return tab_array.size } } + binding.tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { + override fun onTabSelected(tab: TabLayout.Tab?){} + + override fun onTabUnselected(tab: TabLayout.Tab?) {} + + override fun onTabReselected(tab: TabLayout.Tab?) { + tab?.position?.let { position -> + val page = + //No clue why this works but it does. F to pay respects + supportFragmentManager.findFragmentByTag("f$position") + (page as? CachedFeedFragment<*>)?.onTabReClicked() + } + } + }) TabLayoutMediator(binding.tabs, binding.viewPager) { tab, position -> tab.icon = ContextCompat.getDrawable(applicationContext, diff --git a/app/src/main/java/com/h/pixeldroid/postCreation/PostCreationActivity.kt b/app/src/main/java/org/pixeldroid/app/postCreation/PostCreationActivity.kt similarity index 88% rename from app/src/main/java/com/h/pixeldroid/postCreation/PostCreationActivity.kt rename to app/src/main/java/org/pixeldroid/app/postCreation/PostCreationActivity.kt index ae86a40a..8d7ba739 100644 --- a/app/src/main/java/com/h/pixeldroid/postCreation/PostCreationActivity.kt +++ b/app/src/main/java/org/pixeldroid/app/postCreation/PostCreationActivity.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.postCreation +package org.pixeldroid.app.postCreation import android.app.Activity import android.app.AlertDialog @@ -16,29 +16,30 @@ import android.view.View.INVISIBLE import android.view.View.VISIBLE import android.widget.Toast import androidx.activity.result.ActivityResult +import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.core.net.toFile import androidx.core.net.toUri import androidx.lifecycle.lifecycleScope import com.google.android.material.snackbar.Snackbar -import com.h.pixeldroid.MainActivity -import com.h.pixeldroid.R -import com.h.pixeldroid.databinding.ActivityPostCreationBinding -import com.h.pixeldroid.postCreation.camera.CameraActivity -import com.h.pixeldroid.postCreation.carousel.CarouselItem -import com.h.pixeldroid.postCreation.carousel.ImageCarousel -import com.h.pixeldroid.postCreation.photoEdit.PhotoEditActivity -import com.h.pixeldroid.utils.BaseActivity -import com.h.pixeldroid.utils.api.PixelfedAPI -import com.h.pixeldroid.utils.api.objects.Attachment -import com.h.pixeldroid.utils.db.entities.InstanceDatabaseEntity -import com.h.pixeldroid.utils.db.entities.UserDatabaseEntity +import org.pixeldroid.app.MainActivity +import org.pixeldroid.app.R +import org.pixeldroid.app.databinding.ActivityPostCreationBinding +import org.pixeldroid.app.postCreation.camera.CameraActivity +import org.pixeldroid.app.postCreation.carousel.CarouselItem +import org.pixeldroid.app.postCreation.carousel.ImageCarousel +import org.pixeldroid.app.postCreation.photoEdit.PhotoEditActivity +import org.pixeldroid.app.utils.BaseActivity +import org.pixeldroid.app.utils.api.objects.Attachment +import org.pixeldroid.app.utils.db.entities.InstanceDatabaseEntity +import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers import okhttp3.MultipartBody import retrofit2.HttpException import java.io.File +import java.io.FileNotFoundException import java.io.IOException import java.io.OutputStream import java.text.SimpleDateFormat @@ -58,9 +59,6 @@ data class PhotoData( class PostCreationActivity : BaseActivity() { - private lateinit var accessToken: String - private lateinit var pixelfedAPI: PixelfedAPI - private var user: UserDatabaseEntity? = null private lateinit var instance: InstanceDatabaseEntity @@ -86,9 +84,6 @@ class PostCreationActivity : BaseActivity() { // get image URIs intent.clipData?.let { addPossibleImages(it) } - accessToken = user?.accessToken.orEmpty() - pixelfedAPI = apiHolder.api ?: apiHolder.setDomainToCurrentUser(db) - val carousel: ImageCarousel = binding.carousel carousel.addData(photoData.map { CarouselItem(it.imageUri) }) carousel.layoutCarouselCallback = { @@ -105,7 +100,7 @@ class PostCreationActivity : BaseActivity() { addPhoto() } carousel.updateDescriptionCallback = { position: Int, description: String -> - photoData[position].imageDescription = description + photoData.getOrNull(position)?.imageDescription = description } // get the description and send the post @@ -319,7 +314,16 @@ class PostCreationActivity : BaseActivity() { for (data: PhotoData in photoData) { val imageUri = data.imageUri - val imageInputStream = contentResolver.openInputStream(imageUri)!! + val imageInputStream = try { + contentResolver.openInputStream(imageUri)!! + } catch (e: FileNotFoundException){ + AlertDialog.Builder(this).apply { + setMessage(getString(R.string.file_not_found).format(imageUri)) + + setNegativeButton(android.R.string.ok) { _, _ -> } + }.show() + return + } val imagePart = ProgressRequestBody(imageInputStream, data.size) val requestBody = MultipartBody.Builder() @@ -339,8 +343,8 @@ class PostCreationActivity : BaseActivity() { val description = data.imageDescription?.let { MultipartBody.Part.createFormData("description", it) } - - val inter = pixelfedAPI.mediaUpload("Bearer $accessToken", description, requestBody.parts[0]) + val api = apiHolder.api ?: apiHolder.setToCurrentUser() + val inter = api.mediaUpload(description, requestBody.parts[0]) postSub = inter .subscribeOn(Schedulers.io()) @@ -382,8 +386,9 @@ class PostCreationActivity : BaseActivity() { enableButton(false) lifecycleScope.launchWhenCreated { try { - pixelfedAPI.postStatus( - authorization = "Bearer $accessToken", + val api = apiHolder.api ?: apiHolder.setToCurrentUser() + + api.postStatus( statusText = description, media_ids = photoData.mapNotNull { it.uploadId }.toList() ) @@ -418,18 +423,18 @@ class PostCreationActivity : BaseActivity() { } - private fun editResultContract(position: Int) = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){ + private val editResultContract: ActivityResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){ result: ActivityResult? -> if (result?.resultCode == Activity.RESULT_OK && result.data != null) { - photoData[position].apply { - imageUri = result.data!!.getStringExtra("result")!!.toUri() + val position: Int = result.data!!.getIntExtra(PhotoEditActivity.PICTURE_POSITION, 0) + photoData.getOrNull(position)?.apply { + imageUri = result.data!!.getStringExtra(PhotoEditActivity.PICTURE_URI)!!.toUri() size = imageUri.getSize() - } + progress = null + uploadId = null + } ?: Toast.makeText(applicationContext, "Error while editing", Toast.LENGTH_SHORT).show() binding.carousel.addData(photoData.map { CarouselItem(it.imageUri, it.imageDescription) }) - - photoData[position].progress = null - photoData[position].uploadId = null } else if(result?.resultCode != Activity.RESULT_CANCELED){ Toast.makeText(applicationContext, "Error while editing", Toast.LENGTH_SHORT).show() } @@ -437,8 +442,8 @@ class PostCreationActivity : BaseActivity() { private fun edit(position: Int) { val intent = Intent(this, PhotoEditActivity::class.java) - .putExtra("picture_uri", photoData[position].imageUri) - .putExtra("no upload", false) - editResultContract(position).launch(intent) + .putExtra(PhotoEditActivity.PICTURE_URI, photoData[position].imageUri) + .putExtra(PhotoEditActivity.PICTURE_POSITION, position) + editResultContract.launch(intent) } } \ No newline at end of file diff --git a/app/src/main/java/com/h/pixeldroid/postCreation/ProgressRequestBody.kt b/app/src/main/java/org/pixeldroid/app/postCreation/ProgressRequestBody.kt similarity index 97% rename from app/src/main/java/com/h/pixeldroid/postCreation/ProgressRequestBody.kt rename to app/src/main/java/org/pixeldroid/app/postCreation/ProgressRequestBody.kt index 62587bea..3893b754 100644 --- a/app/src/main/java/com/h/pixeldroid/postCreation/ProgressRequestBody.kt +++ b/app/src/main/java/org/pixeldroid/app/postCreation/ProgressRequestBody.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.postCreation +package org.pixeldroid.app.postCreation import io.reactivex.Observable import io.reactivex.subjects.PublishSubject diff --git a/app/src/main/java/com/h/pixeldroid/postCreation/SquareLayout.kt b/app/src/main/java/org/pixeldroid/app/postCreation/SquareLayout.kt similarity index 89% rename from app/src/main/java/com/h/pixeldroid/postCreation/SquareLayout.kt rename to app/src/main/java/org/pixeldroid/app/postCreation/SquareLayout.kt index a93dd3f0..cbee61a6 100644 --- a/app/src/main/java/com/h/pixeldroid/postCreation/SquareLayout.kt +++ b/app/src/main/java/org/pixeldroid/app/postCreation/SquareLayout.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.postCreation +package org.pixeldroid.app.postCreation import android.content.Context import android.util.AttributeSet diff --git a/app/src/main/java/com/h/pixeldroid/postCreation/camera/CameraActivity.kt b/app/src/main/java/org/pixeldroid/app/postCreation/camera/CameraActivity.kt similarity index 74% rename from app/src/main/java/com/h/pixeldroid/postCreation/camera/CameraActivity.kt rename to app/src/main/java/org/pixeldroid/app/postCreation/camera/CameraActivity.kt index 9a57109e..42f8f517 100644 --- a/app/src/main/java/com/h/pixeldroid/postCreation/camera/CameraActivity.kt +++ b/app/src/main/java/org/pixeldroid/app/postCreation/camera/CameraActivity.kt @@ -1,8 +1,8 @@ -package com.h.pixeldroid.postCreation.camera +package org.pixeldroid.app.postCreation.camera import android.os.Bundle -import com.h.pixeldroid.utils.BaseActivity -import com.h.pixeldroid.R +import org.pixeldroid.app.utils.BaseActivity +import org.pixeldroid.app.R class CameraActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { @@ -20,9 +20,4 @@ class CameraActivity : BaseActivity() { supportFragmentManager.beginTransaction() .add(R.id.camera_activity_fragment, cameraFragment).commit() } - - override fun onSupportNavigateUp(): Boolean { - onBackPressed() - return true - } } \ No newline at end of file diff --git a/app/src/main/java/com/h/pixeldroid/postCreation/camera/CameraFragment.kt b/app/src/main/java/org/pixeldroid/app/postCreation/camera/CameraFragment.kt similarity index 99% rename from app/src/main/java/com/h/pixeldroid/postCreation/camera/CameraFragment.kt rename to app/src/main/java/org/pixeldroid/app/postCreation/camera/CameraFragment.kt index a98ded92..43191527 100644 --- a/app/src/main/java/com/h/pixeldroid/postCreation/camera/CameraFragment.kt +++ b/app/src/main/java/org/pixeldroid/app/postCreation/camera/CameraFragment.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.postCreation.camera +package org.pixeldroid.app.postCreation.camera import android.Manifest import android.app.Activity @@ -31,8 +31,8 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import com.bumptech.glide.Glide import com.bumptech.glide.request.RequestOptions -import com.h.pixeldroid.R -import com.h.pixeldroid.postCreation.PostCreationActivity +import org.pixeldroid.app.R +import org.pixeldroid.app.postCreation.PostCreationActivity import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import java.io.File diff --git a/app/src/main/java/com/h/pixeldroid/postCreation/carousel/CarouselAdapter.kt b/app/src/main/java/org/pixeldroid/app/postCreation/carousel/CarouselAdapter.kt similarity index 93% rename from app/src/main/java/com/h/pixeldroid/postCreation/carousel/CarouselAdapter.kt rename to app/src/main/java/org/pixeldroid/app/postCreation/carousel/CarouselAdapter.kt index 759343fc..ca2c6384 100644 --- a/app/src/main/java/com/h/pixeldroid/postCreation/carousel/CarouselAdapter.kt +++ b/app/src/main/java/org/pixeldroid/app/postCreation/carousel/CarouselAdapter.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.postCreation.carousel +package org.pixeldroid.app.postCreation.carousel import android.graphics.drawable.Drawable import android.view.LayoutInflater @@ -9,7 +9,7 @@ import androidx.annotation.IdRes import androidx.annotation.LayoutRes import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide -import com.h.pixeldroid.R +import org.pixeldroid.app.R class CarouselAdapter( @@ -96,8 +96,10 @@ class CarouselAdapter( } fun updateDescription(position: Int, description: String) { - dataList[position] = dataList[position].copy(caption = description) - notifyItemChanged(position) + dataList.getOrNull(position)?.apply { + dataList[position] = copy(caption = description) + notifyItemChanged(position) + } } fun addAll(dataList: List) { diff --git a/app/src/main/java/com/h/pixeldroid/postCreation/carousel/CarouselItem.kt b/app/src/main/java/org/pixeldroid/app/postCreation/carousel/CarouselItem.kt similarity index 78% rename from app/src/main/java/com/h/pixeldroid/postCreation/carousel/CarouselItem.kt rename to app/src/main/java/org/pixeldroid/app/postCreation/carousel/CarouselItem.kt index 8b3ef70e..4e6f854e 100644 --- a/app/src/main/java/com/h/pixeldroid/postCreation/carousel/CarouselItem.kt +++ b/app/src/main/java/org/pixeldroid/app/postCreation/carousel/CarouselItem.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.postCreation.carousel +package org.pixeldroid.app.postCreation.carousel import android.net.Uri diff --git a/app/src/main/java/com/h/pixeldroid/postCreation/carousel/CarouselLinearLayoutManager.kt b/app/src/main/java/org/pixeldroid/app/postCreation/carousel/CarouselLinearLayoutManager.kt similarity index 91% rename from app/src/main/java/com/h/pixeldroid/postCreation/carousel/CarouselLinearLayoutManager.kt rename to app/src/main/java/org/pixeldroid/app/postCreation/carousel/CarouselLinearLayoutManager.kt index 71b9e626..ad5753f2 100644 --- a/app/src/main/java/com/h/pixeldroid/postCreation/carousel/CarouselLinearLayoutManager.kt +++ b/app/src/main/java/org/pixeldroid/app/postCreation/carousel/CarouselLinearLayoutManager.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.postCreation.carousel +package org.pixeldroid.app.postCreation.carousel import android.content.Context import androidx.recyclerview.widget.LinearLayoutManager diff --git a/app/src/main/java/com/h/pixeldroid/postCreation/carousel/ImageCarousel.kt b/app/src/main/java/org/pixeldroid/app/postCreation/carousel/ImageCarousel.kt similarity index 97% rename from app/src/main/java/com/h/pixeldroid/postCreation/carousel/ImageCarousel.kt rename to app/src/main/java/org/pixeldroid/app/postCreation/carousel/ImageCarousel.kt index 88a7913b..a95ed00d 100644 --- a/app/src/main/java/com/h/pixeldroid/postCreation/carousel/ImageCarousel.kt +++ b/app/src/main/java/org/pixeldroid/app/postCreation/carousel/ImageCarousel.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.postCreation.carousel +package org.pixeldroid.app.postCreation.carousel import android.content.Context import android.graphics.Color @@ -15,8 +15,8 @@ import androidx.annotation.LayoutRes import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.ContextCompat import androidx.recyclerview.widget.* -import com.h.pixeldroid.R -import com.h.pixeldroid.databinding.ImageCarouselBinding +import org.pixeldroid.app.R +import org.pixeldroid.app.databinding.ImageCarouselBinding import me.relex.circleindicator.CircleIndicator2 import org.jetbrains.annotations.NotNull import org.jetbrains.annotations.Nullable @@ -44,7 +44,6 @@ class ImageCarousel( private lateinit var recyclerView: RecyclerView private lateinit var tvCaption: TextView - private lateinit var editTextMediaDescription: EditText private var snapHelper: SnapHelper = PagerSnapHelper() var indicator: CircleIndicator2? = null @@ -292,9 +291,9 @@ class ImageCarousel( if(layoutCarousel){ field = value - if(value) editTextMediaDescription.setText(currentDescription) + if(value) binding.editTextMediaDescription.setText(currentDescription) else { - val description = editTextMediaDescription.text.toString() + val description = binding.editTextMediaDescription.text.toString() currentDescription = description adapter?.updateDescription(currentPosition, description) updateDescriptionCallback?.invoke(currentPosition, description) @@ -339,7 +338,6 @@ class ImageCarousel( recyclerView = binding.recyclerView tvCaption = binding.tvCaption - editTextMediaDescription = binding.editTextMediaDescription recyclerView.setHasFixedSize(true) diff --git a/app/src/main/java/com/h/pixeldroid/postCreation/carousel/Utils.kt b/app/src/main/java/org/pixeldroid/app/postCreation/carousel/Utils.kt similarity index 96% rename from app/src/main/java/com/h/pixeldroid/postCreation/carousel/Utils.kt rename to app/src/main/java/org/pixeldroid/app/postCreation/carousel/Utils.kt index ac6431ed..4f60e488 100644 --- a/app/src/main/java/com/h/pixeldroid/postCreation/carousel/Utils.kt +++ b/app/src/main/java/org/pixeldroid/app/postCreation/carousel/Utils.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.postCreation.carousel +package org.pixeldroid.app.postCreation.carousel import android.content.Context import android.util.DisplayMetrics diff --git a/app/src/main/java/com/h/pixeldroid/postCreation/photoEdit/EditImageFragment.kt b/app/src/main/java/org/pixeldroid/app/postCreation/photoEdit/EditImageFragment.kt similarity index 97% rename from app/src/main/java/com/h/pixeldroid/postCreation/photoEdit/EditImageFragment.kt rename to app/src/main/java/org/pixeldroid/app/postCreation/photoEdit/EditImageFragment.kt index 6234c110..1602ac88 100644 --- a/app/src/main/java/com/h/pixeldroid/postCreation/photoEdit/EditImageFragment.kt +++ b/app/src/main/java/org/pixeldroid/app/postCreation/photoEdit/EditImageFragment.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.postCreation.photoEdit +package org.pixeldroid.app.postCreation.photoEdit import android.os.Bundle import androidx.fragment.app.Fragment @@ -6,7 +6,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.SeekBar -import com.h.pixeldroid.R +import org.pixeldroid.app.R class EditImageFragment : Fragment(), SeekBar.OnSeekBarChangeListener { diff --git a/app/src/main/java/com/h/pixeldroid/postCreation/photoEdit/EditPhotoViewPagerAdapter.kt b/app/src/main/java/org/pixeldroid/app/postCreation/photoEdit/EditPhotoViewPagerAdapter.kt similarity index 93% rename from app/src/main/java/com/h/pixeldroid/postCreation/photoEdit/EditPhotoViewPagerAdapter.kt rename to app/src/main/java/org/pixeldroid/app/postCreation/photoEdit/EditPhotoViewPagerAdapter.kt index 06a7a57c..db23f72e 100644 --- a/app/src/main/java/com/h/pixeldroid/postCreation/photoEdit/EditPhotoViewPagerAdapter.kt +++ b/app/src/main/java/org/pixeldroid/app/postCreation/photoEdit/EditPhotoViewPagerAdapter.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.postCreation.photoEdit +package org.pixeldroid.app.postCreation.photoEdit import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager diff --git a/app/src/main/java/com/h/pixeldroid/postCreation/photoEdit/FilterListFragment.kt b/app/src/main/java/org/pixeldroid/app/postCreation/photoEdit/FilterListFragment.kt similarity index 98% rename from app/src/main/java/com/h/pixeldroid/postCreation/photoEdit/FilterListFragment.kt rename to app/src/main/java/org/pixeldroid/app/postCreation/photoEdit/FilterListFragment.kt index b8f7fef0..fd449696 100644 --- a/app/src/main/java/com/h/pixeldroid/postCreation/photoEdit/FilterListFragment.kt +++ b/app/src/main/java/org/pixeldroid/app/postCreation/photoEdit/FilterListFragment.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.postCreation.photoEdit +package org.pixeldroid.app.postCreation.photoEdit import android.graphics.Bitmap import android.os.Bundle @@ -11,7 +11,7 @@ import androidx.fragment.app.Fragment import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView -import com.h.pixeldroid.R +import org.pixeldroid.app.R import com.zomato.photofilters.FilterPack import com.zomato.photofilters.imageprocessors.Filter import com.zomato.photofilters.utils.ThumbnailItem diff --git a/app/src/main/java/com/h/pixeldroid/postCreation/photoEdit/NonSwipeableViewPager.kt b/app/src/main/java/org/pixeldroid/app/postCreation/photoEdit/NonSwipeableViewPager.kt similarity index 96% rename from app/src/main/java/com/h/pixeldroid/postCreation/photoEdit/NonSwipeableViewPager.kt rename to app/src/main/java/org/pixeldroid/app/postCreation/photoEdit/NonSwipeableViewPager.kt index 5fecbf38..4e7145b4 100644 --- a/app/src/main/java/com/h/pixeldroid/postCreation/photoEdit/NonSwipeableViewPager.kt +++ b/app/src/main/java/org/pixeldroid/app/postCreation/photoEdit/NonSwipeableViewPager.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.postCreation.photoEdit +package org.pixeldroid.app.postCreation.photoEdit import android.content.Context import android.util.AttributeSet diff --git a/app/src/main/java/com/h/pixeldroid/postCreation/photoEdit/PhotoEditActivity.kt b/app/src/main/java/org/pixeldroid/app/postCreation/photoEdit/PhotoEditActivity.kt similarity index 95% rename from app/src/main/java/com/h/pixeldroid/postCreation/photoEdit/PhotoEditActivity.kt rename to app/src/main/java/org/pixeldroid/app/postCreation/photoEdit/PhotoEditActivity.kt index 058aede1..c1abd83a 100644 --- a/app/src/main/java/com/h/pixeldroid/postCreation/photoEdit/PhotoEditActivity.kt +++ b/app/src/main/java/org/pixeldroid/app/postCreation/photoEdit/PhotoEditActivity.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.postCreation.photoEdit +package org.pixeldroid.app.postCreation.photoEdit import android.app.Activity import android.app.AlertDialog @@ -18,14 +18,11 @@ import android.widget.Toast import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import com.bumptech.glide.Glide -import com.google.android.material.floatingactionbutton.FloatingActionButton import com.google.android.material.snackbar.Snackbar -import com.google.android.material.tabs.TabLayout -import com.h.pixeldroid.R -import com.h.pixeldroid.databinding.ActivityPhotoEditBinding -import com.h.pixeldroid.databinding.ActivityPostCreationBinding -import com.h.pixeldroid.postCreation.PostCreationActivity -import com.h.pixeldroid.utils.BaseActivity +import org.pixeldroid.app.R +import org.pixeldroid.app.databinding.ActivityPhotoEditBinding +import org.pixeldroid.app.postCreation.PostCreationActivity +import org.pixeldroid.app.utils.BaseActivity import com.yalantis.ucrop.UCrop import com.zomato.photofilters.imageprocessors.Filter import com.zomato.photofilters.imageprocessors.subfilters.BrightnessSubFilter @@ -65,6 +62,8 @@ class PhotoEditActivity : BaseActivity() { private lateinit var filterListFragment: FilterListFragment private lateinit var editImageFragment: EditImageFragment + private var picturePosition: Int? = null + private var brightnessFinal = BRIGHTNESS_START private var saturationFinal = SATURATION_START private var contrastFinal = CONTRAST_START @@ -74,6 +73,9 @@ class PhotoEditActivity : BaseActivity() { } companion object{ + internal const val PICTURE_URI = "picture_uri" + internal const val PICTURE_POSITION = "picture_position" + private var executor: ExecutorService = newSingleThreadExecutor() private var future: Future<*>? = null @@ -97,7 +99,8 @@ class PhotoEditActivity : BaseActivity() { supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setHomeButtonEnabled(true) - initialUri = intent.getParcelableExtra("picture_uri") + initialUri = intent.getParcelableExtra(PICTURE_URI) + picturePosition = intent.getIntExtra(PICTURE_POSITION, 0) imageUri = initialUri // Crop button on-click listener @@ -342,7 +345,8 @@ class PhotoEditActivity : BaseActivity() { private fun sendBackImage(file: String) { val intent = Intent(this, PostCreationActivity::class.java) .apply { - putExtra("result", file) + putExtra(PICTURE_URI, file) + putExtra(PICTURE_POSITION, picturePosition) addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) } diff --git a/app/src/main/java/com/h/pixeldroid/postCreation/photoEdit/SpaceItemDecoration.kt b/app/src/main/java/org/pixeldroid/app/postCreation/photoEdit/SpaceItemDecoration.kt similarity index 91% rename from app/src/main/java/com/h/pixeldroid/postCreation/photoEdit/SpaceItemDecoration.kt rename to app/src/main/java/org/pixeldroid/app/postCreation/photoEdit/SpaceItemDecoration.kt index dbef867f..b720aba9 100644 --- a/app/src/main/java/com/h/pixeldroid/postCreation/photoEdit/SpaceItemDecoration.kt +++ b/app/src/main/java/org/pixeldroid/app/postCreation/photoEdit/SpaceItemDecoration.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.postCreation.photoEdit +package org.pixeldroid.app.postCreation.photoEdit import android.graphics.Rect import android.view.View diff --git a/app/src/main/java/com/h/pixeldroid/postCreation/photoEdit/ThumbnailAdapter.kt b/app/src/main/java/org/pixeldroid/app/postCreation/photoEdit/ThumbnailAdapter.kt similarity index 93% rename from app/src/main/java/com/h/pixeldroid/postCreation/photoEdit/ThumbnailAdapter.kt rename to app/src/main/java/org/pixeldroid/app/postCreation/photoEdit/ThumbnailAdapter.kt index 51f0e143..89daa23d 100644 --- a/app/src/main/java/com/h/pixeldroid/postCreation/photoEdit/ThumbnailAdapter.kt +++ b/app/src/main/java/org/pixeldroid/app/postCreation/photoEdit/ThumbnailAdapter.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.postCreation.photoEdit +package org.pixeldroid.app.postCreation.photoEdit import android.content.Context import android.view.LayoutInflater @@ -7,8 +7,8 @@ import android.widget.ImageView import android.widget.TextView import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView -import com.h.pixeldroid.R -import com.h.pixeldroid.databinding.ThumbnailListItemBinding +import org.pixeldroid.app.R +import org.pixeldroid.app.databinding.ThumbnailListItemBinding import com.zomato.photofilters.utils.ThumbnailItem class ThumbnailAdapter (private val context: Context, diff --git a/app/src/main/java/com/h/pixeldroid/posts/ClickableSpanNoUnderline.kt b/app/src/main/java/org/pixeldroid/app/posts/ClickableSpanNoUnderline.kt similarity index 88% rename from app/src/main/java/com/h/pixeldroid/posts/ClickableSpanNoUnderline.kt rename to app/src/main/java/org/pixeldroid/app/posts/ClickableSpanNoUnderline.kt index 45d9261d..b6258cb2 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/ClickableSpanNoUnderline.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/ClickableSpanNoUnderline.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.posts +package org.pixeldroid.app.posts import android.text.TextPaint import android.text.style.ClickableSpan diff --git a/app/src/main/java/com/h/pixeldroid/posts/HtmlUtils.kt b/app/src/main/java/org/pixeldroid/app/posts/HtmlUtils.kt similarity index 86% rename from app/src/main/java/com/h/pixeldroid/posts/HtmlUtils.kt rename to app/src/main/java/org/pixeldroid/app/posts/HtmlUtils.kt index 9db5428a..3af59d1a 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/HtmlUtils.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/HtmlUtils.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.posts +package org.pixeldroid.app.posts import android.content.Context import android.os.Build @@ -12,13 +12,13 @@ import android.view.View import android.widget.TextView import android.widget.Toast import androidx.core.text.toSpanned -import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleCoroutineScope -import com.h.pixeldroid.R -import com.h.pixeldroid.utils.api.PixelfedAPI -import com.h.pixeldroid.utils.api.objects.Account.Companion.openAccountFromId -import com.h.pixeldroid.utils.api.objects.Mention -import kotlinx.coroutines.coroutineScope +import org.pixeldroid.app.R +import org.pixeldroid.app.utils.api.PixelfedAPI +import org.pixeldroid.app.utils.api.objects.Account.Companion.openAccountFromId +import org.pixeldroid.app.utils.api.objects.Mention +import org.pixeldroid.app.utils.api.objects.Tag.Companion.openTag +import org.pixeldroid.app.utils.di.PixelfedAPIHolder import java.net.URI import java.net.URISyntaxException import java.text.ParseException @@ -50,12 +50,11 @@ fun getDomain(urlString: String?): String { } fun parseHTMLText( - text : String, - mentions: List?, - api : PixelfedAPI, - context: Context, - credential: String, - lifecycleScope: LifecycleCoroutineScope + text: String, + mentions: List?, + apiHolder: PixelfedAPIHolder, + context: Context, + lifecycleScope: LifecycleCoroutineScope, ) : Spanned { //Convert text to spannable val content = fromHtml(text) @@ -76,7 +75,7 @@ fun parseHTMLText( val tag = text.subSequence(1, text.length).toString() customSpan = object : ClickableSpanNoUnderline() { override fun onClick(widget: View) { - Toast.makeText(context, tag, Toast.LENGTH_SHORT).show() + openTag(context, tag) } } @@ -108,7 +107,8 @@ fun parseHTMLText( Log.e("MENTION", "CLICKED") //Retrieve the account for the given profile lifecycleScope.launchWhenCreated { - openAccountFromId(accountId, api, context, credential) + val api: PixelfedAPI = apiHolder.api ?: apiHolder.setToCurrentUser() + openAccountFromId(accountId, api, context) } } } diff --git a/app/src/main/java/com/h/pixeldroid/posts/NestedScrollableHost.kt b/app/src/main/java/org/pixeldroid/app/posts/NestedScrollableHost.kt similarity index 92% rename from app/src/main/java/com/h/pixeldroid/posts/NestedScrollableHost.kt rename to app/src/main/java/org/pixeldroid/app/posts/NestedScrollableHost.kt index 49b3ac60..fa0157d7 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/NestedScrollableHost.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/NestedScrollableHost.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.h.pixeldroid.posts +package org.pixeldroid.app.posts import android.content.Context import android.util.AttributeSet @@ -51,7 +51,7 @@ class NestedScrollableHost : ConstraintLayout { return v as? ViewPager2 } - var doubleTapCallback: ((Unit) -> Unit)? = null + var doubleTapCallback: ((Boolean) -> Unit)? = null private val child: View? get() = if (childCount > 0) getChildAt(0) else null @@ -79,7 +79,7 @@ class NestedScrollableHost : ConstraintLayout { if (e.action == MotionEvent.ACTION_DOWN) { initialX = e.x initialY = e.y - doubleTapCallback?.invoke(Unit) + doubleTapCallback?.invoke(true) } // Early return if child can't scroll in same direction as parent if (!canChildScroll(orientation, -1f) && !canChildScroll(orientation, 1f)) { @@ -94,10 +94,13 @@ class NestedScrollableHost : ConstraintLayout { val isVpHorizontal = orientation == ORIENTATION_HORIZONTAL // assuming ViewPager2 touch-slop is 2x touch-slop of child - val scaledDx = dx.absoluteValue * if (isVpHorizontal) .5f else 1f - val scaledDy = dy.absoluteValue * if (isVpHorizontal) 1f else .5f + val scaledDx = dx.absoluteValue * if (isVpHorizontal) .5f/ touchSlopModifier else 1f + val scaledDy = dy.absoluteValue * if (isVpHorizontal) 1f else .5f/touchSlopModifier + + if(dx.absoluteValue * .5f > touchSlop || scaledDy > touchSlop) doubleTapCallback?.invoke(false) if (scaledDx > touchSlop || scaledDy > touchSlop) { + if (isVpHorizontal == (scaledDy > scaledDx)) { // Gesture is perpendicular, allow all parents to intercept parent.requestDisallowInterceptTouchEvent(false) @@ -114,4 +117,8 @@ class NestedScrollableHost : ConstraintLayout { } } } + + companion object { + const val touchSlopModifier = 2 + } } \ No newline at end of file diff --git a/app/src/main/java/com/h/pixeldroid/posts/PostActivity.kt b/app/src/main/java/org/pixeldroid/app/posts/PostActivity.kt similarity index 72% rename from app/src/main/java/com/h/pixeldroid/posts/PostActivity.kt rename to app/src/main/java/org/pixeldroid/app/posts/PostActivity.kt index c7d6d0c6..ff263970 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/PostActivity.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/PostActivity.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.posts +package org.pixeldroid.app.posts import android.content.Context import android.os.Bundle @@ -9,23 +9,22 @@ import android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE import android.widget.LinearLayout import android.widget.Toast import androidx.lifecycle.lifecycleScope -import com.h.pixeldroid.R -import com.h.pixeldroid.databinding.ActivityPostBinding -import com.h.pixeldroid.databinding.CommentBinding -import com.h.pixeldroid.utils.BaseActivity -import com.h.pixeldroid.utils.api.PixelfedAPI -import com.h.pixeldroid.utils.api.objects.Mention -import com.h.pixeldroid.utils.api.objects.Status -import com.h.pixeldroid.utils.api.objects.Status.Companion.POST_COMMENT_TAG -import com.h.pixeldroid.utils.api.objects.Status.Companion.POST_TAG -import com.h.pixeldroid.utils.api.objects.Status.Companion.VIEW_COMMENTS_TAG -import com.h.pixeldroid.utils.displayDimensionsInPx +import org.pixeldroid.app.R +import org.pixeldroid.app.databinding.ActivityPostBinding +import org.pixeldroid.app.databinding.CommentBinding +import org.pixeldroid.app.utils.BaseActivity +import org.pixeldroid.app.utils.api.PixelfedAPI +import org.pixeldroid.app.utils.api.objects.Mention +import org.pixeldroid.app.utils.api.objects.Status +import org.pixeldroid.app.utils.api.objects.Status.Companion.POST_COMMENT_TAG +import org.pixeldroid.app.utils.api.objects.Status.Companion.POST_TAG +import org.pixeldroid.app.utils.api.objects.Status.Companion.VIEW_COMMENTS_TAG +import org.pixeldroid.app.utils.displayDimensionsInPx import retrofit2.HttpException import java.io.IOException class PostActivity : BaseActivity() { lateinit var domain : String - private lateinit var accessToken : String private lateinit var binding: ActivityPostBinding @@ -45,17 +44,15 @@ class PostActivity : BaseActivity() { val user = db.userDao().getActiveUser() domain = user?.instance_uri.orEmpty() - accessToken = user?.accessToken.orEmpty() supportActionBar?.title = getString(R.string.post_title).format(status.account?.getusername()) val holder = StatusViewHolder(binding.postFragmentSingle) - holder.bind(status, apiHolder.api!!, db, lifecycleScope, displayDimensionsInPx(), isActivity = true) + holder.bind(status, apiHolder, db, lifecycleScope, displayDimensionsInPx(), isActivity = true) - val credential = "Bearer $accessToken" - activateCommenter(credential) + activateCommenter() if(viewComments || postComment){ //Scroll already down as much as possible (since comments are not loaded yet) @@ -68,19 +65,14 @@ class PostActivity : BaseActivity() { } // also retrieve comments if we're not posting the comment - if(!postComment) retrieveComments(apiHolder.api!!, credential) + if(!postComment) retrieveComments(apiHolder.api!!) } binding.postFragmentSingle.viewComments.setOnClickListener { - retrieveComments(apiHolder.api!!, credential) + retrieveComments(apiHolder.api!!) } } - override fun onSupportNavigateUp(): Boolean { - onBackPressed() - return true - } - - private fun activateCommenter(credential: String) { + private fun activateCommenter() { //Activate commenter binding.submitComment.setOnClickListener { val textIn = binding.editComment.text @@ -94,15 +86,14 @@ class PostActivity : BaseActivity() { } else { //Post the comment lifecycleScope.launchWhenCreated { - apiHolder.api?.let { it1 -> postComment(it1, credential) } + apiHolder.api?.let { it1 -> postComment(it1) } } } } } private fun addComment(context: Context, commentContainer: LinearLayout, - commentUsername: String, commentContent: String, mentions: List, - credential: String) { + commentUsername: String, commentContent: String, mentions: List) { val itemBinding = CommentBinding.inflate( @@ -111,27 +102,30 @@ class PostActivity : BaseActivity() { itemBinding.user.text = commentUsername itemBinding.commentText.text = parseHTMLText( - commentContent, - mentions, - apiHolder.api!!, - context, - credential, - lifecycleScope + commentContent, + mentions, + apiHolder, + context, + lifecycleScope ) } - private fun retrieveComments(api: PixelfedAPI, credential: String) { + private fun retrieveComments(api: PixelfedAPI) { lifecycleScope.launchWhenCreated { status.id.let { try { - val statuses = api.statusComments(it, credential).descendants + val statuses = api.statusComments(it).descendants binding.commentContainer.removeAllViews() //Create the new views for each comment for (status in statuses) { - addComment(binding.root.context, binding.commentContainer, status.account!!.username!!, - status.content!!, status.mentions.orEmpty(), credential + addComment( + binding.root.context, + binding.commentContainer, + status.account!!.username!!, + status.content!!, + status.mentions.orEmpty() ) } binding.commentContainer.visibility = View.VISIBLE @@ -149,19 +143,18 @@ class PostActivity : BaseActivity() { private suspend fun postComment( api: PixelfedAPI, - credential: String, ) { val textIn = binding.editComment.text val nonNullText = textIn.toString() status.id.let { try { - val response = api.postStatus(credential, nonNullText, it) + val response = api.postStatus(nonNullText, it) binding.commentIn.visibility = View.GONE //Add the comment to the comment section addComment( binding.root.context, binding.commentContainer, response.account!!.username!!, - response.content!!, response.mentions.orEmpty(), credential + response.content!!, response.mentions.orEmpty() ) Toast.makeText( diff --git a/app/src/main/java/com/h/pixeldroid/posts/ReportActivity.kt b/app/src/main/java/org/pixeldroid/app/posts/ReportActivity.kt similarity index 74% rename from app/src/main/java/com/h/pixeldroid/posts/ReportActivity.kt rename to app/src/main/java/org/pixeldroid/app/posts/ReportActivity.kt index aa52ac5a..e9ab3aae 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/ReportActivity.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/ReportActivity.kt @@ -1,12 +1,12 @@ -package com.h.pixeldroid.posts +package org.pixeldroid.app.posts import android.os.Bundle import android.view.View import androidx.lifecycle.lifecycleScope -import com.h.pixeldroid.R -import com.h.pixeldroid.databinding.ActivityReportBinding -import com.h.pixeldroid.utils.BaseActivity -import com.h.pixeldroid.utils.api.objects.Status +import org.pixeldroid.app.R +import org.pixeldroid.app.databinding.ActivityReportBinding +import org.pixeldroid.app.utils.BaseActivity +import org.pixeldroid.app.utils.api.objects.Status import retrofit2.HttpException import java.io.IOException @@ -24,10 +24,6 @@ class ReportActivity : BaseActivity() { val status = intent.getSerializableExtra(Status.POST_TAG) as Status? - //get the currently active user - val user = db.userDao().getActiveUser() - - binding.reportTargetTextview.text = getString(R.string.report_target).format(status?.account?.acct) @@ -37,12 +33,15 @@ class ReportActivity : BaseActivity() { binding.textInputLayout.editText?.isEnabled = false - val accessToken = user?.accessToken.orEmpty() - val api = apiHolder.api ?: apiHolder.setDomainToCurrentUser(db) + val api = apiHolder.api ?: apiHolder.setToCurrentUser() lifecycleScope.launchWhenCreated { try { - api.report("Bearer $accessToken", status?.account?.id!!, listOf(status), binding.textInputLayout.editText?.text.toString()) + api.report( + status?.account?.id!!, + listOf(status), + binding.textInputLayout.editText?.text.toString() + ) reportStatus(true) } catch (exception: IOException) { @@ -67,9 +66,4 @@ class ReportActivity : BaseActivity() { binding.reportProgressBar.visibility = View.GONE } } - - override fun onSupportNavigateUp(): Boolean { - onBackPressed() - return true - } } \ No newline at end of file diff --git a/app/src/main/java/com/h/pixeldroid/posts/StatusViewHolder.kt b/app/src/main/java/org/pixeldroid/app/posts/StatusViewHolder.kt similarity index 86% rename from app/src/main/java/com/h/pixeldroid/posts/StatusViewHolder.kt rename to app/src/main/java/org/pixeldroid/app/posts/StatusViewHolder.kt index 77b061b7..b8c110ed 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/StatusViewHolder.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/StatusViewHolder.kt @@ -1,9 +1,10 @@ -package com.h.pixeldroid.posts +package org.pixeldroid.app.posts import android.Manifest import android.app.AlertDialog import android.content.Intent import android.graphics.Typeface +import android.graphics.drawable.AnimatedVectorDrawable import android.graphics.drawable.Drawable import android.text.method.LinkMovementMethod import android.util.Log @@ -14,21 +15,23 @@ import android.widget.* import androidx.core.content.ContextCompat import androidx.lifecycle.LifecycleCoroutineScope import androidx.recyclerview.widget.RecyclerView +import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat import com.bumptech.glide.Glide import com.bumptech.glide.RequestBuilder import com.google.android.material.snackbar.Snackbar -import com.h.pixeldroid.R -import com.h.pixeldroid.databinding.AlbumImageViewBinding -import com.h.pixeldroid.databinding.PostFragmentBinding -import com.h.pixeldroid.utils.BlurHashDecoder -import com.h.pixeldroid.utils.ImageConverter -import com.h.pixeldroid.utils.api.PixelfedAPI -import com.h.pixeldroid.utils.api.objects.Attachment -import com.h.pixeldroid.utils.api.objects.Status -import com.h.pixeldroid.utils.api.objects.Status.Companion.POST_COMMENT_TAG -import com.h.pixeldroid.utils.api.objects.Status.Companion.POST_TAG -import com.h.pixeldroid.utils.api.objects.Status.Companion.VIEW_COMMENTS_TAG -import com.h.pixeldroid.utils.db.AppDatabase +import org.pixeldroid.app.R +import org.pixeldroid.app.databinding.AlbumImageViewBinding +import org.pixeldroid.app.databinding.PostFragmentBinding +import org.pixeldroid.app.utils.BlurHashDecoder +import org.pixeldroid.app.utils.ImageConverter +import org.pixeldroid.app.utils.api.PixelfedAPI +import org.pixeldroid.app.utils.api.objects.Attachment +import org.pixeldroid.app.utils.api.objects.Status +import org.pixeldroid.app.utils.api.objects.Status.Companion.POST_COMMENT_TAG +import org.pixeldroid.app.utils.api.objects.Status.Companion.POST_TAG +import org.pixeldroid.app.utils.api.objects.Status.Companion.VIEW_COMMENTS_TAG +import org.pixeldroid.app.utils.db.AppDatabase +import org.pixeldroid.app.utils.di.PixelfedAPIHolder import com.karumi.dexter.Dexter import com.karumi.dexter.listener.PermissionDeniedResponse import com.karumi.dexter.listener.PermissionGrantedResponse @@ -46,7 +49,7 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold private var status: Status? = null - fun bind(status: Status?, pixelfedAPI: PixelfedAPI, db: AppDatabase, lifecycleScope: LifecycleCoroutineScope, displayDimensionsInPx: Pair, isActivity: Boolean = false) { + fun bind(status: Status?, pixelfedAPI: PixelfedAPIHolder, db: AppDatabase, lifecycleScope: LifecycleCoroutineScope, displayDimensionsInPx: Pair, isActivity: Boolean = false) { this.itemView.visibility = View.VISIBLE this.status = status @@ -177,21 +180,19 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold } private fun setDescription( - api: PixelfedAPI, - credential: String, - lifecycleScope: LifecycleCoroutineScope + apiHolder: PixelfedAPIHolder, + lifecycleScope: LifecycleCoroutineScope, ) { binding.description.apply { if (status?.content.isNullOrBlank()) { visibility = View.GONE } else { text = parseHTMLText( - status?.content.orEmpty(), - status?.mentions, - api, - binding.root.context, - credential, - lifecycleScope + status?.content.orEmpty(), + status?.mentions, + apiHolder, + binding.root.context, + lifecycleScope ) movementMethod = LinkMovementMethod.getInstance() } @@ -199,25 +200,20 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold } //region buttons private fun activateButtons( - api: PixelfedAPI, + apiHolder: PixelfedAPIHolder, db: AppDatabase, lifecycleScope: LifecycleCoroutineScope, isActivity: Boolean ){ - val user = db.userDao().getActiveUser()!! - - val credential = "Bearer ${user.accessToken}" //Set the special HTML text - setDescription(api, credential, lifecycleScope) + setDescription(apiHolder, lifecycleScope) //Activate onclickListeners activateLiker( - api, credential, status?.favourited ?: false, - lifecycleScope + apiHolder, status?.favourited ?: false, lifecycleScope ) activateReblogger( - api, credential, status?.reblogged ?: false, - lifecycleScope + apiHolder, status?.reblogged ?: false, lifecycleScope ) if(isActivity){ @@ -237,14 +233,13 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold showComments(lifecycleScope, isActivity) - activateMoreButton(api, db, lifecycleScope) + activateMoreButton(apiHolder, db, lifecycleScope) } private fun activateReblogger( - api: PixelfedAPI, - credential: String, - isReblogged: Boolean, - lifecycleScope: LifecycleCoroutineScope + apiHolder: PixelfedAPIHolder, + isReblogged: Boolean, + lifecycleScope: LifecycleCoroutineScope, ) { binding.reblogger.apply { //Set initial button state @@ -253,12 +248,13 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold //Activate the button setEventListener { _, buttonState -> lifecycleScope.launchWhenCreated { + val api: PixelfedAPI = apiHolder.api ?: apiHolder.setToCurrentUser() if (buttonState) { // Button is active - undoReblogPost(api, credential) + undoReblogPost(api) } else { // Button is inactive - reblogPost(api, credential) + reblogPost(api) } } //show animation or not? @@ -267,15 +263,12 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold } } - private suspend fun reblogPost( - api: PixelfedAPI, - credential: String - ) { + private suspend fun reblogPost(api: PixelfedAPI) { //Call the api function status?.id?.let { try { - val resp = api.reblogStatus(credential, it) + val resp = api.reblogStatus(it) //Update shown share count binding.nshares.text = resp.getNShares(binding.root.context) @@ -290,14 +283,11 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold } } - private suspend fun undoReblogPost( - api: PixelfedAPI, - credential: String, - ) { + private suspend fun undoReblogPost(api: PixelfedAPI) { //Call the api function status?.id?.let { try { - val resp = api.undoReblogStatus(credential, it) + val resp = api.undoReblogStatus(it) //Update shown share count binding.nshares.text = resp.getNShares(binding.root.context) @@ -312,7 +302,7 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold } } - private fun activateMoreButton(api: PixelfedAPI, db: AppDatabase, lifecycleScope: LifecycleCoroutineScope){ + private fun activateMoreButton(apiHolder: PixelfedAPIHolder, db: AppDatabase, lifecycleScope: LifecycleCoroutineScope){ binding.statusMore.setOnClickListener { PopupMenu(it.context, it).apply { setOnMenuItemClickListener { item -> @@ -395,7 +385,8 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold db.homePostDao().delete(id, user.user_id, user.instance_uri) db.publicPostDao().delete(id, user.user_id, user.instance_uri) try { - api.deleteStatus("Bearer ${user.accessToken}", id) + val api = apiHolder.api ?: apiHolder.setToCurrentUser() + api.deleteStatus(id) binding.root.visibility = View.GONE } catch (exception: HttpException) { Toast.makeText( @@ -439,10 +430,9 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold } private fun activateLiker( - api: PixelfedAPI, - credential: String, - isLiked: Boolean, - lifecycleScope: LifecycleCoroutineScope + apiHolder: PixelfedAPIHolder, + isLiked: Boolean, + lifecycleScope: LifecycleCoroutineScope, ) { binding.liker.apply { @@ -452,12 +442,13 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold //Activate the liker setEventListener { _, buttonState -> lifecycleScope.launchWhenCreated { + val api: PixelfedAPI = apiHolder.api ?: apiHolder.setToCurrentUser() if (buttonState) { // Button is active, unlike - unLikePostCall(api, credential) + unLikePostCall(api) } else { // Button is inactive, like - likePostCall(api, credential) + likePostCall(api) } } //show animation or not? @@ -468,20 +459,23 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold //Activate double tap liking var clicked = false binding.postPagerHost.doubleTapCallback = { - lifecycleScope.launchWhenCreated { + if(!it) clicked = false + else lifecycleScope.launchWhenCreated { //Check that the post isn't hidden if(binding.sensitiveWarning.visibility == View.GONE) { //Check for double click if(clicked) { + val api: PixelfedAPI = apiHolder.api ?: apiHolder.setToCurrentUser() if (binding.liker.isChecked) { // Button is active, unlike binding.liker.isChecked = false - unLikePostCall(api, credential) + unLikePostCall(api) } else { // Button is inactive, like binding.liker.playAnimation() binding.liker.isChecked = true - likePostCall(api, credential) + binding.likeAnimation.animateView() + likePostCall(api) } } else { clicked = true @@ -490,20 +484,27 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold binding.postPager.handler.postDelayed(fun() { clicked = false }, 500) } } - + } + } + } + private fun ImageView.animateView() { + visibility = View.VISIBLE + when (val drawable = drawable) { + is AnimatedVectorDrawableCompat -> { + drawable.start() + } + is AnimatedVectorDrawable -> { + drawable.start() } } } - private suspend fun likePostCall( - api: PixelfedAPI, - credential: String, - ) { + private suspend fun likePostCall(api: PixelfedAPI) { //Call the api function status?.id?.let { try { - val resp = api.likePost(credential, it) + val resp = api.likePost(it) //Update shown like count and internal like toggle binding.nlikes.text = resp.getNLikes(binding.root.context) @@ -518,15 +519,12 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold } } - private suspend fun unLikePostCall( - api: PixelfedAPI, - credential: String, - ) { + private suspend fun unLikePostCall(api: PixelfedAPI) { //Call the api function status?.id?.let { try { - val resp = api.unlikePost(credential, it) + val resp = api.unlikePost(it) //Update shown like count and internal like toggle binding.nlikes.text = resp.getNLikes(binding.root.context) diff --git a/app/src/main/java/com/h/pixeldroid/posts/feeds/CommonFeedFragmentUtils.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/CommonFeedFragmentUtils.kt similarity index 70% rename from app/src/main/java/com/h/pixeldroid/posts/feeds/CommonFeedFragmentUtils.kt rename to app/src/main/java/org/pixeldroid/app/posts/feeds/CommonFeedFragmentUtils.kt index 0c773afd..76c008d4 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/feeds/CommonFeedFragmentUtils.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/CommonFeedFragmentUtils.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.posts.feeds +package org.pixeldroid.app.posts.feeds import android.view.LayoutInflater import android.view.ViewGroup @@ -12,14 +12,16 @@ import androidx.paging.LoadStateAdapter import androidx.paging.PagingDataAdapter import androidx.recyclerview.widget.RecyclerView import androidx.swiperefreshlayout.widget.SwipeRefreshLayout -import com.h.pixeldroid.R -import com.h.pixeldroid.databinding.ErrorLayoutBinding -import com.h.pixeldroid.databinding.LoadStateFooterViewItemBinding -import com.h.pixeldroid.posts.feeds.uncachedFeeds.FeedViewModel -import com.h.pixeldroid.utils.api.objects.FeedContent +import com.google.gson.Gson +import org.pixeldroid.app.R +import org.pixeldroid.app.databinding.ErrorLayoutBinding +import org.pixeldroid.app.databinding.LoadStateFooterViewItemBinding +import org.pixeldroid.app.posts.feeds.uncachedFeeds.FeedViewModel +import org.pixeldroid.app.utils.api.objects.FeedContent import kotlinx.coroutines.Job import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch +import retrofit2.HttpException /** * Shows or hides the error in the different FeedFragments @@ -56,24 +58,17 @@ internal fun initAdapter( if(!progressBar.isVisible && swipeRefreshLayout.isRefreshing) { // Stop loading spinner when loading is done swipeRefreshLayout.isRefreshing = loadState.refresh is LoadState.Loading - } else { - // ProgressBar should stop showing as soon as the source stops loading ("source" - // meaning the database, so don't wait on the network) - val sourceLoading = loadState.source.refresh is LoadState.Loading - if(!sourceLoading && recyclerView.size > 0){ - recyclerView.isVisible = true - progressBar.isVisible = false - } else if(recyclerView.size == 0 - && loadState.append is LoadState.NotLoading - && loadState.append.endOfPaginationReached){ - progressBar.isVisible = false - showError(motionLayout = motionLayout, errorLayout = errorLayout, - errorText = errorLayout.root.context.getString(R.string.empty_feed)) - } } + // ProgressBar should stop showing as soon as the source stops loading ("source" + // meaning the database, so don't wait on the network) + val sourceLoading = loadState.source.refresh is LoadState.Loading + if (!sourceLoading && adapter.itemCount > 0) { + recyclerView.isVisible = true + progressBar.isVisible = false + } - // Toast on any error, regardless of whether it came from RemoteMediator or PagingSource + // Show any error, regardless of whether it came from RemoteMediator or PagingSource val errorState = loadState.source.append as? LoadState.Error ?: loadState.source.prepend as? LoadState.Error ?: loadState.source.refresh as? LoadState.Error @@ -81,21 +76,37 @@ internal fun initAdapter( ?: loadState.prepend as? LoadState.Error ?: loadState.refresh as? LoadState.Error errorState?.let { - showError(motionLayout = motionLayout, errorLayout = errorLayout, errorText = it.error.toString()) + val error: String = (it.error as? HttpException)?.response()?.errorBody()?.string()?.ifEmpty { null }?.let { s -> + Gson().fromJson(s, org.pixeldroid.app.utils.api.objects.Error::class.java)?.error?.ifBlank { null } + } ?: it.error.localizedMessage.orEmpty() + showError(motionLayout = motionLayout, errorLayout = errorLayout, errorText = error) } + + // If the state is not an error, hide the error layout, or show message that the feed is empty if(errorState == null) { - showError(motionLayout = motionLayout, errorLayout = errorLayout, show = false, errorText = "") + if (adapter.itemCount == 0 + && loadState.append is LoadState.NotLoading + && loadState.append.endOfPaginationReached + ) { + progressBar.isVisible = false + showError( + motionLayout = motionLayout, errorLayout = errorLayout, + errorText = errorLayout.root.context.getString(R.string.empty_feed) + ) + } else { + showError(motionLayout = motionLayout, errorLayout = errorLayout, show = false, errorText = "") + } } } } -fun launch( - job: Job?, lifecycleScope: LifecycleCoroutineScope, viewModel: FeedViewModel, - pagingDataAdapter: PagingDataAdapter): Job { +fun launch( + job: Job?, lifecycleScope: LifecycleCoroutineScope, viewModel: FeedViewModel, + pagingDataAdapter: PagingDataAdapter): Job { // Make sure we cancel the previous job before creating a new one job?.cancel() return lifecycleScope.launch { - viewModel.flow().collectLatest { + viewModel.flow.collectLatest { pagingDataAdapter.submitData(it) } } diff --git a/app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/CachedFeedFragment.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/CachedFeedFragment.kt similarity index 74% rename from app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/CachedFeedFragment.kt rename to app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/CachedFeedFragment.kt index a9af376b..57ace3a4 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/CachedFeedFragment.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/CachedFeedFragment.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.posts.feeds.cachedFeeds +package org.pixeldroid.app.posts.feeds.cachedFeeds import android.os.Bundle import android.view.LayoutInflater @@ -8,21 +8,18 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.paging.* +import androidx.paging.LoadState.* +import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.distinctUntilChangedBy -import kotlinx.coroutines.flow.filter -import kotlinx.coroutines.launch - -import com.h.pixeldroid.databinding.FragmentFeedBinding -import com.h.pixeldroid.utils.db.AppDatabase -import com.h.pixeldroid.utils.db.dao.feedContent.FeedContentDao -import com.h.pixeldroid.utils.BaseFragment -import com.h.pixeldroid.posts.feeds.initAdapter -import com.h.pixeldroid.utils.api.objects.FeedContentDatabase - +import kotlinx.coroutines.flow.* +import org.pixeldroid.app.databinding.FragmentFeedBinding +import org.pixeldroid.app.posts.feeds.initAdapter +import org.pixeldroid.app.utils.BaseFragment +import org.pixeldroid.app.utils.api.objects.FeedContentDatabase +import org.pixeldroid.app.utils.db.AppDatabase +import org.pixeldroid.app.utils.db.dao.feedContent.FeedContentDao +import org.pixeldroid.app.utils.limitedLengthSmoothScrollToPosition /** * A fragment representing a list of [FeedContentDatabase] items that are cached by the database. @@ -43,7 +40,7 @@ open class CachedFeedFragment : BaseFragment() { // Make sure we cancel the previous job before creating a new one job?.cancel() job = lifecycleScope.launchWhenStarted { - viewModel.flow().collectLatest { + viewModel.flow.collectLatest { adapter.submitData(it) } } @@ -51,12 +48,14 @@ open class CachedFeedFragment : BaseFragment() { internal fun initSearch() { // Scroll to top when the list is refreshed from network. - lifecycleScope.launch { + lifecycleScope.launchWhenStarted { adapter.loadStateFlow // Only emit when REFRESH LoadState for RemoteMediator changes. - .distinctUntilChangedBy { it.refresh } + .distinctUntilChangedBy { + it.refresh + } // Only react to cases where Remote REFRESH completes i.e., NotLoading. - .filter { it.refresh is LoadState.NotLoading } + .filter { it.refresh is NotLoading} .collect { binding.list.scrollToPosition(0) } } } @@ -73,17 +72,16 @@ open class CachedFeedFragment : BaseFragment() { initAdapter(binding.progressBar, binding.swipeRefreshLayout, binding.list, binding.motionLayout, binding.errorLayout, adapter) - //binding.progressBar.visibility = View.GONE binding.swipeRefreshLayout.setOnRefreshListener { - //It shouldn't be necessary to also retry() in addition to refresh(), - //but if we don't do this, reloads after an error fail immediately... - // https://issuetracker.google.com/issues/173438474 - adapter.retry() adapter.refresh() } return binding.root } + + fun onTabReClicked() { + binding.list.limitedLengthSmoothScrollToPosition(0) + } } diff --git a/app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/FeedContentRepository.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/FeedContentRepository.kt similarity index 88% rename from app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/FeedContentRepository.kt rename to app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/FeedContentRepository.kt index 8477b2e7..e18b5720 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/FeedContentRepository.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/FeedContentRepository.kt @@ -14,12 +14,12 @@ * limitations under the License. */ -package com.h.pixeldroid.posts.feeds.cachedFeeds +package org.pixeldroid.app.posts.feeds.cachedFeeds import androidx.paging.* -import com.h.pixeldroid.utils.db.AppDatabase -import com.h.pixeldroid.utils.db.dao.feedContent.FeedContentDao -import com.h.pixeldroid.utils.api.objects.FeedContentDatabase +import org.pixeldroid.app.utils.db.AppDatabase +import org.pixeldroid.app.utils.db.dao.feedContent.FeedContentDao +import org.pixeldroid.app.utils.api.objects.FeedContentDatabase import kotlinx.coroutines.flow.Flow import javax.inject.Inject diff --git a/app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/FeedViewModel.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/FeedViewModel.kt similarity index 60% rename from app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/FeedViewModel.kt rename to app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/FeedViewModel.kt index ac436408..f82d10e0 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/FeedViewModel.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/FeedViewModel.kt @@ -14,31 +14,20 @@ * limitations under the License. */ -package com.h.pixeldroid.posts.feeds.cachedFeeds +package org.pixeldroid.app.posts.feeds.cachedFeeds import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.paging.* -import com.h.pixeldroid.utils.api.objects.FeedContentDatabase +import org.pixeldroid.app.utils.api.objects.FeedContentDatabase import kotlinx.coroutines.flow.Flow /** * ViewModel for the cached feeds. * The ViewModel works with the [FeedContentRepository] to get the data. */ -class FeedViewModel(private val repository: FeedContentRepository) : ViewModel() { - - private var currentResult: Flow>? = null +class FeedViewModel(repository: FeedContentRepository) : ViewModel() { @ExperimentalPagingApi - fun flow(): Flow> { - val lastResult = currentResult - if (lastResult != null) { - return lastResult - } - val newResult: Flow> = repository.stream() - .cachedIn(viewModelScope) - currentResult = newResult - return newResult - } + val flow: Flow> = repository.stream().cachedIn(viewModelScope) } diff --git a/app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/notifications/NotificationsFragment.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/notifications/NotificationsFragment.kt similarity index 83% rename from app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/notifications/NotificationsFragment.kt rename to app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/notifications/NotificationsFragment.kt index 27911329..0dab91ee 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/notifications/NotificationsFragment.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/notifications/NotificationsFragment.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.posts.feeds.cachedFeeds.notifications +package org.pixeldroid.app.posts.feeds.cachedFeeds.notifications import android.content.Context import android.content.Intent @@ -18,21 +18,19 @@ import androidx.paging.PagingDataAdapter import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide -import com.h.pixeldroid.R -import com.h.pixeldroid.databinding.FragmentNotificationsBinding -import com.h.pixeldroid.posts.PostActivity -import com.h.pixeldroid.posts.feeds.cachedFeeds.CachedFeedFragment -import com.h.pixeldroid.posts.feeds.cachedFeeds.FeedViewModel -import com.h.pixeldroid.posts.feeds.cachedFeeds.ViewModelFactory -import com.h.pixeldroid.posts.parseHTMLText -import com.h.pixeldroid.posts.setTextViewFromISO8601 -import com.h.pixeldroid.profile.ProfileActivity -import com.h.pixeldroid.utils.api.PixelfedAPI -import com.h.pixeldroid.utils.api.objects.Account -import com.h.pixeldroid.utils.api.objects.Notification -import com.h.pixeldroid.utils.api.objects.Status -import com.h.pixeldroid.utils.db.AppDatabase -import com.h.pixeldroid.utils.di.PixelfedAPIHolder +import org.pixeldroid.app.R +import org.pixeldroid.app.databinding.FragmentNotificationsBinding +import org.pixeldroid.app.posts.PostActivity +import org.pixeldroid.app.posts.feeds.cachedFeeds.CachedFeedFragment +import org.pixeldroid.app.posts.feeds.cachedFeeds.FeedViewModel +import org.pixeldroid.app.posts.feeds.cachedFeeds.ViewModelFactory +import org.pixeldroid.app.posts.parseHTMLText +import org.pixeldroid.app.posts.setTextViewFromISO8601 +import org.pixeldroid.app.profile.ProfileActivity +import org.pixeldroid.app.utils.api.objects.Account +import org.pixeldroid.app.utils.api.objects.Notification +import org.pixeldroid.app.utils.api.objects.Status +import org.pixeldroid.app.utils.di.PixelfedAPIHolder /** @@ -42,7 +40,7 @@ class NotificationsFragment : CachedFeedFragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - adapter = NotificationsAdapter(apiHolder, db) + adapter = NotificationsAdapter(apiHolder) } @ExperimentalPagingApi @@ -55,10 +53,10 @@ class NotificationsFragment : CachedFeedFragment() { // get the view model @Suppress("UNCHECKED_CAST") viewModel = ViewModelProvider( - this, + requireActivity(), ViewModelFactory(db, db.notificationDao(), NotificationsRemoteMediator(apiHolder, db)) ) - .get(FeedViewModel::class.java) as FeedViewModel + .get("notifications", FeedViewModel::class.java) as FeedViewModel launch() initSearch() @@ -165,9 +163,8 @@ class NotificationsFragment : CachedFeedFragment() { fun bind( notification: Notification?, - api: PixelfedAPI, - accessToken: String, - lifecycleScope: LifecycleCoroutineScope + api: PixelfedAPIHolder, + lifecycleScope: LifecycleCoroutineScope, ) { this.notification = notification @@ -204,12 +201,11 @@ class NotificationsFragment : CachedFeedFragment() { //Convert HTML to clickable text postDescription.text = parseHTMLText( - notification?.status?.content ?: "", - notification?.status?.mentions, - api, - itemView.context, - "Bearer $accessToken", - lifecycleScope + notification?.status?.content ?: "", + notification?.status?.mentions, + api, + itemView.context, + lifecycleScope ) } @@ -226,7 +222,6 @@ class NotificationsFragment : CachedFeedFragment() { inner class NotificationsAdapter( private val apiHolder: PixelfedAPIHolder, - private val db: AppDatabase ) : PagingDataAdapter( object : DiffUtil.ItemCallback() { override fun areItemsTheSame( @@ -256,10 +251,9 @@ class NotificationsFragment : CachedFeedFragment() { val uiModel = getItem(position) uiModel.let { (holder as NotificationViewHolder).bind( - it, - apiHolder.setDomainToCurrentUser(db), - db.userDao().getActiveUser()!!.accessToken, - lifecycleScope + it, + apiHolder, + lifecycleScope ) } } diff --git a/app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/notifications/NotificationsRemoteMediator.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/notifications/NotificationsRemoteMediator.kt similarity index 81% rename from app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/notifications/NotificationsRemoteMediator.kt rename to app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/notifications/NotificationsRemoteMediator.kt index edb5297c..7fbeff26 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/notifications/NotificationsRemoteMediator.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/notifications/NotificationsRemoteMediator.kt @@ -14,13 +14,13 @@ * limitations under the License. */ -package com.h.pixeldroid.posts.feeds.cachedFeeds.notifications +package org.pixeldroid.app.posts.feeds.cachedFeeds.notifications import androidx.paging.* import androidx.room.withTransaction -import com.h.pixeldroid.utils.db.AppDatabase -import com.h.pixeldroid.utils.di.PixelfedAPIHolder -import com.h.pixeldroid.utils.api.objects.Notification +import org.pixeldroid.app.utils.db.AppDatabase +import org.pixeldroid.app.utils.di.PixelfedAPIHolder +import org.pixeldroid.app.utils.api.objects.Notification import retrofit2.HttpException import java.io.IOException import java.lang.NullPointerException @@ -58,13 +58,12 @@ class NotificationsRemoteMediator @Inject constructor( try { val user = db.userDao().getActiveUser() ?: return MediatorResult.Error(NullPointerException("No active user exists")) - val api = apiHolder.api ?: apiHolder.setDomainToCurrentUser(db) - val accessToken = user.accessToken + val api = apiHolder.api ?: apiHolder.setToCurrentUser() - val apiResponse = api.notifications("Bearer $accessToken", - max_id = max_id, - min_id = min_id, - limit = state.config.pageSize.toString(), + val apiResponse = api.notifications( + max_id = max_id, + min_id = min_id, + limit = state.config.pageSize.toString(), ) apiResponse.forEach{it.user_id = user.user_id; it.instance_uri = user.instance_uri} diff --git a/app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/postFeeds/HomeFeedRemoteMediator.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/postFeeds/HomeFeedRemoteMediator.kt similarity index 78% rename from app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/postFeeds/HomeFeedRemoteMediator.kt rename to app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/postFeeds/HomeFeedRemoteMediator.kt index 5f626993..cf6cad08 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/postFeeds/HomeFeedRemoteMediator.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/postFeeds/HomeFeedRemoteMediator.kt @@ -1,10 +1,10 @@ -package com.h.pixeldroid.posts.feeds.cachedFeeds.postFeeds +package org.pixeldroid.app.posts.feeds.cachedFeeds.postFeeds import androidx.paging.* import androidx.room.withTransaction -import com.h.pixeldroid.utils.db.AppDatabase -import com.h.pixeldroid.utils.di.PixelfedAPIHolder -import com.h.pixeldroid.utils.db.entities.HomeStatusDatabaseEntity +import org.pixeldroid.app.utils.db.AppDatabase +import org.pixeldroid.app.utils.di.PixelfedAPIHolder +import org.pixeldroid.app.utils.db.entities.HomeStatusDatabaseEntity import retrofit2.HttpException import java.io.IOException import java.lang.NullPointerException @@ -43,12 +43,12 @@ class HomeFeedRemoteMediator @Inject constructor( try { val user = db.userDao().getActiveUser() ?: return MediatorResult.Error(NullPointerException("No active user exists")) - val api = apiHolder.api ?: apiHolder.setDomainToCurrentUser(db) - val accessToken = user.accessToken + val api = apiHolder.api ?: apiHolder.setToCurrentUser() - val apiResponse = api.timelineHome( "Bearer $accessToken", - max_id= max_id, min_id = min_id, - limit = state.config.pageSize.toString()) + val apiResponse = api.timelineHome( + max_id= max_id, + min_id = min_id, limit = state.config.pageSize.toString() + ) val dbObjects = apiResponse.map{ HomeStatusDatabaseEntity(user.user_id, user.instance_uri, it) diff --git a/app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/postFeeds/PostFeedFragment.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/postFeeds/PostFeedFragment.kt similarity index 64% rename from app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/postFeeds/PostFeedFragment.kt rename to app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/postFeeds/PostFeedFragment.kt index 132fff05..693f43ba 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/postFeeds/PostFeedFragment.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/postFeeds/PostFeedFragment.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.posts.feeds.cachedFeeds.postFeeds +package org.pixeldroid.app.posts.feeds.cachedFeeds.postFeeds import android.os.Bundle import android.view.LayoutInflater @@ -11,15 +11,16 @@ import androidx.paging.PagingDataAdapter import androidx.paging.RemoteMediator import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView -import com.h.pixeldroid.R -import com.h.pixeldroid.utils.db.dao.feedContent.FeedContentDao -import com.h.pixeldroid.posts.StatusViewHolder -import com.h.pixeldroid.posts.feeds.cachedFeeds.FeedViewModel -import com.h.pixeldroid.posts.feeds.cachedFeeds.CachedFeedFragment -import com.h.pixeldroid.posts.feeds.cachedFeeds.ViewModelFactory -import com.h.pixeldroid.utils.api.objects.FeedContentDatabase -import com.h.pixeldroid.utils.api.objects.Status -import com.h.pixeldroid.utils.displayDimensionsInPx +import org.pixeldroid.app.R +import org.pixeldroid.app.utils.db.dao.feedContent.FeedContentDao +import org.pixeldroid.app.posts.StatusViewHolder +import org.pixeldroid.app.posts.feeds.cachedFeeds.FeedViewModel +import org.pixeldroid.app.posts.feeds.cachedFeeds.CachedFeedFragment +import org.pixeldroid.app.posts.feeds.cachedFeeds.ViewModelFactory +import org.pixeldroid.app.utils.api.objects.FeedContentDatabase +import org.pixeldroid.app.utils.api.objects.Status +import org.pixeldroid.app.utils.displayDimensionsInPx +import kotlin.properties.Delegates /** @@ -32,14 +33,17 @@ class PostFeedFragment: CachedFeedFragment() { private lateinit var mediator: RemoteMediator private lateinit var dao: FeedContentDao + private var home by Delegates.notNull() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) adapter = PostsAdapter(requireContext().displayDimensionsInPx()) + home = requireArguments().get("home") as Boolean + @Suppress("UNCHECKED_CAST") - if (requireArguments().get("home") as Boolean){ + if (home){ mediator = HomeFeedRemoteMediator(apiHolder, db) as RemoteMediator dao = db.homePostDao() as FeedContentDao } @@ -59,8 +63,8 @@ class PostFeedFragment: CachedFeedFragment() { // get the view model @Suppress("UNCHECKED_CAST") - viewModel = ViewModelProvider(this, ViewModelFactory(db, dao, mediator)) - .get(FeedViewModel::class.java) as FeedViewModel + viewModel = ViewModelProvider(requireActivity(), ViewModelFactory(db, dao, mediator)) + .get(if(home) "home" else "public", FeedViewModel::class.java) as FeedViewModel launch() initSearch() @@ -70,12 +74,8 @@ class PostFeedFragment: CachedFeedFragment() { inner class PostsAdapter(private val displayDimensionsInPx: Pair) : PagingDataAdapter( object : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: T, newItem: T): Boolean { - return oldItem.id == newItem.id - } - - override fun areContentsTheSame(oldItem: T, newItem: T): Boolean = - oldItem.id == newItem.id + override fun areItemsTheSame (oldItem: T, newItem: T): Boolean = oldItem.id == newItem.id + override fun areContentsTheSame(oldItem: T, newItem: T): Boolean = oldItem.id == newItem.id } ) { @@ -88,9 +88,9 @@ class PostFeedFragment: CachedFeedFragment() { } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { - val uiModel = getItem(position) as Status - uiModel.let { - (holder as StatusViewHolder).bind(it, apiHolder.setDomainToCurrentUser(db), db, lifecycleScope, displayDimensionsInPx) + val uiModel = getItem(position) as Status? + uiModel?.let { + (holder as StatusViewHolder).bind(it, apiHolder, db, lifecycleScope, displayDimensionsInPx) } } } diff --git a/app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/postFeeds/PublicFeedRemoteMediator.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/postFeeds/PublicFeedRemoteMediator.kt similarity index 91% rename from app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/postFeeds/PublicFeedRemoteMediator.kt rename to app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/postFeeds/PublicFeedRemoteMediator.kt index 0d061bbd..bb68f3df 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/feeds/cachedFeeds/postFeeds/PublicFeedRemoteMediator.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/postFeeds/PublicFeedRemoteMediator.kt @@ -14,13 +14,13 @@ * limitations under the License. */ -package com.h.pixeldroid.posts.feeds.cachedFeeds.postFeeds +package org.pixeldroid.app.posts.feeds.cachedFeeds.postFeeds import androidx.paging.* import androidx.room.withTransaction -import com.h.pixeldroid.utils.db.AppDatabase -import com.h.pixeldroid.utils.db.entities.PublicFeedStatusDatabaseEntity -import com.h.pixeldroid.utils.di.PixelfedAPIHolder +import org.pixeldroid.app.utils.db.AppDatabase +import org.pixeldroid.app.utils.db.entities.PublicFeedStatusDatabaseEntity +import org.pixeldroid.app.utils.di.PixelfedAPIHolder import retrofit2.HttpException import java.io.IOException import java.lang.NullPointerException @@ -58,7 +58,7 @@ class PublicFeedRemoteMediator @Inject constructor( try { val user = db.userDao().getActiveUser() ?: return MediatorResult.Error(NullPointerException("No active user exists")) - val api = apiHolder.api ?: apiHolder.setDomainToCurrentUser(db) + val api = apiHolder.api ?: apiHolder.setToCurrentUser() val apiResponse = api.timelinePublic( max_id = max_id, diff --git a/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/FeedViewModel.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/FeedViewModel.kt new file mode 100644 index 00000000..09e60501 --- /dev/null +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/FeedViewModel.kt @@ -0,0 +1,22 @@ +package org.pixeldroid.app.posts.feeds.uncachedFeeds + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import androidx.paging.* +import org.pixeldroid.app.utils.api.objects.FeedContent +import kotlinx.coroutines.flow.Flow + +/** + * ViewModel for the uncached feeds. + * The ViewModel works with the different [UncachedContentRepository]s to get the data. + */ +class FeedViewModel(repository: UncachedContentRepository) : ViewModel() { + val flow: Flow> = repository.getStream().cachedIn(viewModelScope) +} + +/** + * Common interface for the different uncached feeds + */ +interface UncachedContentRepository{ + fun getStream(): Flow> +} \ No newline at end of file diff --git a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/UncachedFeedFragment.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/UncachedFeedFragment.kt similarity index 78% rename from app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/UncachedFeedFragment.kt rename to app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/UncachedFeedFragment.kt index 1e48bf16..adbd5d30 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/UncachedFeedFragment.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/UncachedFeedFragment.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.posts.feeds.uncachedFeeds +package org.pixeldroid.app.posts.feeds.uncachedFeeds import android.os.Bundle import android.view.LayoutInflater @@ -9,17 +9,17 @@ import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.paging.* import androidx.recyclerview.widget.RecyclerView -import com.h.pixeldroid.posts.feeds.launch +import org.pixeldroid.app.posts.feeds.launch import kotlinx.coroutines.Job import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.distinctUntilChangedBy import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch -import com.h.pixeldroid.databinding.FragmentFeedBinding -import com.h.pixeldroid.utils.BaseFragment -import com.h.pixeldroid.posts.feeds.initAdapter -import com.h.pixeldroid.utils.api.objects.FeedContent +import org.pixeldroid.app.databinding.FragmentFeedBinding +import org.pixeldroid.app.utils.BaseFragment +import org.pixeldroid.app.posts.feeds.initAdapter +import org.pixeldroid.app.utils.api.objects.FeedContent /** @@ -37,10 +37,7 @@ open class UncachedFeedFragment : BaseFragment() { internal fun launch() { - @Suppress("UNCHECKED_CAST") - job = launch(job, lifecycleScope, - viewModel as FeedViewModel, - adapter as PagingDataAdapter) + job = launch(job, lifecycleScope, viewModel, adapter) } internal fun initSearch() { @@ -68,9 +65,6 @@ open class UncachedFeedFragment : BaseFragment() { binding.motionLayout, binding.errorLayout, adapter) binding.swipeRefreshLayout.setOnRefreshListener { - //It shouldn't be necessary to also retry() in addition to refresh(), - //but if we don't do this, reloads after an error fail immediately... - adapter.retry() adapter.refresh() } diff --git a/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/UncachedPostsFragment.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/UncachedPostsFragment.kt new file mode 100644 index 00000000..7f503c04 --- /dev/null +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/UncachedPostsFragment.kt @@ -0,0 +1,103 @@ +package org.pixeldroid.app.posts.feeds.uncachedFeeds + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import androidx.paging.ExperimentalPagingApi +import androidx.paging.PagingDataAdapter +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.RecyclerView +import org.pixeldroid.app.R +import org.pixeldroid.app.posts.StatusViewHolder +import org.pixeldroid.app.posts.feeds.uncachedFeeds.hashtags.HashTagContentRepository +import org.pixeldroid.app.posts.feeds.uncachedFeeds.search.SearchContentRepository +import org.pixeldroid.app.utils.api.objects.Results +import org.pixeldroid.app.utils.api.objects.Status +import org.pixeldroid.app.utils.api.objects.Tag.Companion.HASHTAG_TAG +import org.pixeldroid.app.utils.displayDimensionsInPx + +/** + * Fragment to show a list of [Status]es, as a result of a search or a hashtag. + */ +class UncachedPostsFragment : UncachedFeedFragment() { + + private var hashtagOrQuery: String? = null + private var search: Boolean = false + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + adapter = PostsAdapter(requireContext().displayDimensionsInPx()) + + hashtagOrQuery = arguments?.getString(HASHTAG_TAG) + + if(hashtagOrQuery == null){ + search = true + hashtagOrQuery = arguments?.getString("searchFeed")!! + } + } + + @ExperimentalPagingApi + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = super.onCreateView(inflater, container, savedInstanceState) + + // get the view model + @Suppress("UNCHECKED_CAST") + viewModel = if(search) { + ViewModelProvider( + requireActivity(), ViewModelFactory( + SearchContentRepository( + apiHolder.setToCurrentUser(), + Results.SearchType.statuses, + hashtagOrQuery!! + ) + ) + ) + .get("searchPosts", FeedViewModel::class.java) as FeedViewModel + } else { + ViewModelProvider(requireActivity(), ViewModelFactory( + HashTagContentRepository( + apiHolder.setToCurrentUser(), + hashtagOrQuery!! + ) + ) + ) + .get(HASHTAG_TAG, FeedViewModel::class.java) as FeedViewModel + } + + launch() + initSearch() + + return view + } + + inner class PostsAdapter(private val displayDimensionsInPx: Pair) : PagingDataAdapter( + object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: Status, newItem: Status): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSame(oldItem: Status, newItem: Status): Boolean = + oldItem.id == newItem.id + } + ) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return StatusViewHolder.create(parent) + } + + override fun getItemViewType(position: Int): Int = R.layout.post_fragment + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + getItem(position)?.let { + (holder as StatusViewHolder).bind(it, apiHolder, db, lifecycleScope, displayDimensionsInPx) + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/accountLists/AccountListFragment.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/accountLists/AccountListFragment.kt similarity index 82% rename from app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/accountLists/AccountListFragment.kt rename to app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/accountLists/AccountListFragment.kt index 90a5a18b..135d300b 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/accountLists/AccountListFragment.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/accountLists/AccountListFragment.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.posts.feeds.uncachedFeeds.accountLists +package org.pixeldroid.app.posts.feeds.uncachedFeeds.accountLists import android.annotation.SuppressLint import android.os.Bundle @@ -13,14 +13,14 @@ import androidx.paging.PagingDataAdapter import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide -import com.h.pixeldroid.R -import com.h.pixeldroid.databinding.AccountListEntryBinding -import com.h.pixeldroid.posts.feeds.uncachedFeeds.FeedViewModel -import com.h.pixeldroid.posts.feeds.uncachedFeeds.UncachedFeedFragment -import com.h.pixeldroid.posts.feeds.uncachedFeeds.ViewModelFactory -import com.h.pixeldroid.utils.api.objects.Account -import com.h.pixeldroid.utils.api.objects.Account.Companion.ACCOUNT_ID_TAG -import com.h.pixeldroid.utils.api.objects.Account.Companion.FOLLOWERS_TAG +import org.pixeldroid.app.R +import org.pixeldroid.app.databinding.AccountListEntryBinding +import org.pixeldroid.app.posts.feeds.uncachedFeeds.FeedViewModel +import org.pixeldroid.app.posts.feeds.uncachedFeeds.UncachedFeedFragment +import org.pixeldroid.app.posts.feeds.uncachedFeeds.ViewModelFactory +import org.pixeldroid.app.utils.api.objects.Account +import org.pixeldroid.app.utils.api.objects.Account.Companion.ACCOUNT_ID_TAG +import org.pixeldroid.app.utils.api.objects.Account.Companion.FOLLOWERS_TAG /** @@ -52,16 +52,15 @@ class AccountListFragment : UncachedFeedFragment() { // get the view model @Suppress("UNCHECKED_CAST") - viewModel = ViewModelProvider(this, ViewModelFactory( + viewModel = ViewModelProvider(requireActivity(), ViewModelFactory( FollowersContentRepository( - apiHolder.setDomainToCurrentUser(db), - db.userDao().getActiveUser()!!.accessToken, + apiHolder.setToCurrentUser(), id, following ) ) ) - .get(FeedViewModel::class.java) as FeedViewModel + .get("accountList", FeedViewModel::class.java) as FeedViewModel launch() initSearch() diff --git a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/accountLists/FollowersContentRepository.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/accountLists/FollowersContentRepository.kt similarity index 70% rename from app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/accountLists/FollowersContentRepository.kt rename to app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/accountLists/FollowersContentRepository.kt index 72b6dd09..5eb529d0 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/accountLists/FollowersContentRepository.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/accountLists/FollowersContentRepository.kt @@ -1,12 +1,12 @@ -package com.h.pixeldroid.posts.feeds.uncachedFeeds.accountLists +package org.pixeldroid.app.posts.feeds.uncachedFeeds.accountLists import androidx.paging.ExperimentalPagingApi import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.PagingData -import com.h.pixeldroid.utils.api.PixelfedAPI -import com.h.pixeldroid.posts.feeds.uncachedFeeds.UncachedContentRepository -import com.h.pixeldroid.utils.api.objects.Account +import org.pixeldroid.app.utils.api.PixelfedAPI +import org.pixeldroid.app.posts.feeds.uncachedFeeds.UncachedContentRepository +import org.pixeldroid.app.utils.api.objects.Account import kotlinx.coroutines.flow.Flow import javax.inject.Inject @@ -14,7 +14,6 @@ import javax.inject.Inject class FollowersContentRepository @ExperimentalPagingApi @Inject constructor( private val api: PixelfedAPI, - private val accessToken: String, private val accountId: String, private val following: Boolean, ): UncachedContentRepository { @@ -25,7 +24,7 @@ class FollowersContentRepository @ExperimentalPagingApi pageSize = NETWORK_PAGE_SIZE, enablePlaceholders = false), pagingSourceFactory = { - FollowersPagingSource(api, accessToken, accountId, following) + FollowersPagingSource(api, accountId, following) } ).flow } diff --git a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/accountLists/FollowersPagingSource.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/accountLists/FollowersPagingSource.kt similarity index 60% rename from app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/accountLists/FollowersPagingSource.kt rename to app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/accountLists/FollowersPagingSource.kt index d1eb8d8b..38af9ef4 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/accountLists/FollowersPagingSource.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/accountLists/FollowersPagingSource.kt @@ -1,16 +1,14 @@ -package com.h.pixeldroid.posts.feeds.uncachedFeeds.accountLists +package org.pixeldroid.app.posts.feeds.uncachedFeeds.accountLists import androidx.paging.PagingSource import androidx.paging.PagingState -import com.h.pixeldroid.utils.api.PixelfedAPI -import com.h.pixeldroid.utils.api.objects.Account +import org.pixeldroid.app.utils.api.PixelfedAPI +import org.pixeldroid.app.utils.api.objects.Account import retrofit2.HttpException import java.io.IOException -import java.math.BigInteger class FollowersPagingSource( private val api: PixelfedAPI, - private val accessToken: String, private val accountId: String, private val following: Boolean ) : PagingSource() { @@ -22,17 +20,19 @@ class FollowersPagingSource( // Laravel's paging mechanism, while Mastodon uses the Link header for pagination. // No need to know which is which, they should ignore the non-relevant argument if(following) { - api.followers(account_id = accountId, - authorization = "Bearer $accessToken", + api.followers( + account_id = accountId, + max_id = position, limit = params.loadSize, - page = position, - max_id = position) + page = position + ) } else { - api.following(account_id = accountId, - authorization = "Bearer $accessToken", + api.following( + account_id = accountId, + max_id = position, limit = params.loadSize, - page = position, - max_id = position) + page = position + ) } val accounts = if(response.isSuccessful){ @@ -41,25 +41,22 @@ class FollowersPagingSource( throw HttpException(response) } - val nextPosition: String = if(response.headers()["Link"] != null){ - //Header is of the form: + val nextPosition: String = response.headers()["Link"] + // Header is of the form: // Link: ; rel="next", ; rel="prev" // So we want the first max_id value. In case there are arguments after // the max_id in the URL, we make sure to stop at the first '?' - response.headers()["Link"] - .orEmpty() - .substringAfter("max_id=", "") - .substringBefore('?', "") - .substringBefore('>', "") - } else { - // No Link header, so we just increment the position value + ?.substringAfter("max_id=", "") + ?.substringBefore('?', "") + ?.substringBefore('>', "") + + ?: // No Link header, so we just increment the position value (Pixelfed case) (position?.toBigIntegerOrNull() ?: 1.toBigInteger()).inc().toString() - } LoadResult.Page( data = accounts, prevKey = null, - nextKey = if (accounts.isEmpty()) null else nextPosition + nextKey = if (accounts.isEmpty() || nextPosition.isEmpty() || nextPosition == position) null else nextPosition ) } catch (exception: IOException) { LoadResult.Error(exception) @@ -68,8 +65,5 @@ class FollowersPagingSource( } } - override fun getRefreshKey(state: PagingState): String? = - state.anchorPosition?.run { - state.closestItemToPosition(this)?.id - } + override fun getRefreshKey(state: PagingState): String? = null } \ No newline at end of file diff --git a/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/hashtags/HashTagActivity.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/hashtags/HashTagActivity.kt new file mode 100644 index 00000000..c45982b0 --- /dev/null +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/hashtags/HashTagActivity.kt @@ -0,0 +1,35 @@ +package org.pixeldroid.app.posts.feeds.uncachedFeeds.hashtags + +import android.os.Bundle +import org.pixeldroid.app.R +import org.pixeldroid.app.posts.feeds.uncachedFeeds.UncachedPostsFragment +import org.pixeldroid.app.utils.BaseActivity +import org.pixeldroid.app.utils.api.objects.Tag.Companion.HASHTAG_TAG + + +class HashTagActivity : BaseActivity() { + private var tagFragment = UncachedPostsFragment() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_followers) + supportActionBar?.setDisplayHomeAsUpEnabled(true) + + // Get hashtag tag + val tag = intent.getSerializableExtra(HASHTAG_TAG) as String? + + startFragment(tag!!) + } + + private fun startFragment(tag : String) { + supportActionBar?.title = getString(R.string.hashtag_title).format(tag) + + val arguments = Bundle() + arguments.putSerializable(HASHTAG_TAG, tag) + tagFragment.arguments = arguments + + supportFragmentManager.beginTransaction() + .add(R.id.followsFragment, tagFragment).commit() + + } +} diff --git a/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/hashtags/HashTagContentRepository.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/hashtags/HashTagContentRepository.kt new file mode 100644 index 00000000..ce509b0b --- /dev/null +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/hashtags/HashTagContentRepository.kt @@ -0,0 +1,38 @@ +package org.pixeldroid.app.posts.feeds.uncachedFeeds.hashtags + +import androidx.paging.ExperimentalPagingApi +import androidx.paging.Pager +import androidx.paging.PagingConfig +import androidx.paging.PagingData +import org.pixeldroid.app.utils.api.PixelfedAPI +import org.pixeldroid.app.posts.feeds.uncachedFeeds.UncachedContentRepository +import org.pixeldroid.app.utils.api.objects.FeedContent +import org.pixeldroid.app.utils.api.objects.Results +import kotlinx.coroutines.flow.Flow +import org.pixeldroid.app.utils.api.objects.Status +import javax.inject.Inject + +/** + * Repository class for viewing hashtags + */ +class HashTagContentRepository @ExperimentalPagingApi +@Inject constructor( + private val api: PixelfedAPI, + private val hashtag: String, +): UncachedContentRepository { + override fun getStream(): Flow> { + return Pager( + config = PagingConfig( + initialLoadSize = NETWORK_PAGE_SIZE, + pageSize = NETWORK_PAGE_SIZE, + enablePlaceholders = false), + pagingSourceFactory = { + HashTagPagingSource(api, hashtag) + } + ).flow + } + + companion object { + private const val NETWORK_PAGE_SIZE = 20 + } +} \ No newline at end of file diff --git a/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/hashtags/HashTagPagingSource.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/hashtags/HashTagPagingSource.kt new file mode 100644 index 00000000..29903f39 --- /dev/null +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/hashtags/HashTagPagingSource.kt @@ -0,0 +1,47 @@ +package org.pixeldroid.app.posts.feeds.uncachedFeeds.hashtags + +import androidx.paging.PagingSource +import androidx.paging.PagingState +import org.pixeldroid.app.utils.api.PixelfedAPI +import org.pixeldroid.app.utils.api.objects.FeedContent +import org.pixeldroid.app.utils.api.objects.Results +import org.pixeldroid.app.utils.api.objects.Status +import retrofit2.HttpException +import java.io.IOException + +/** + * Provides the PagingSource for hashtag feeds. Is used in [HashTagContentRepository] + */ +class HashTagPagingSource( + private val api: PixelfedAPI, + private val query: String, +) : PagingSource() { + override suspend fun load(params: LoadParams): LoadResult { + val position = params.key + return try { + val response = api.hashtag( + hashtag = query, + limit = params.loadSize, + max_id = position, + ) + + val nextKey = response.lastOrNull()?.id + + LoadResult.Page( + data = response, + prevKey = null, + nextKey = if(nextKey == position) null else nextKey + ) + } catch (exception: HttpException) { + LoadResult.Error(exception) + } catch (exception: IOException) { + LoadResult.Error(exception) + } + } + + /** + * FIXME if implemented with [PagingState.anchorPosition], this breaks refreshes? How is this + * supposed to work? + */ + override fun getRefreshKey(state: PagingState): String? = null +} \ No newline at end of file diff --git a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/profile/ProfileContentRepository.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/profile/ProfileContentRepository.kt similarity index 70% rename from app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/profile/ProfileContentRepository.kt rename to app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/profile/ProfileContentRepository.kt index 292c8b36..11cafd29 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/profile/ProfileContentRepository.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/profile/ProfileContentRepository.kt @@ -1,19 +1,18 @@ -package com.h.pixeldroid.posts.feeds.uncachedFeeds.profile +package org.pixeldroid.app.posts.feeds.uncachedFeeds.profile import androidx.paging.ExperimentalPagingApi import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.PagingData -import com.h.pixeldroid.posts.feeds.uncachedFeeds.UncachedContentRepository -import com.h.pixeldroid.utils.api.PixelfedAPI -import com.h.pixeldroid.utils.api.objects.Status +import org.pixeldroid.app.posts.feeds.uncachedFeeds.UncachedContentRepository +import org.pixeldroid.app.utils.api.PixelfedAPI +import org.pixeldroid.app.utils.api.objects.Status import kotlinx.coroutines.flow.Flow import javax.inject.Inject class ProfileContentRepository @ExperimentalPagingApi @Inject constructor( private val api: PixelfedAPI, - private val accessToken: String, private val accountId: String ) : UncachedContentRepository { override fun getStream(): Flow> { @@ -23,7 +22,7 @@ class ProfileContentRepository @ExperimentalPagingApi pageSize = NETWORK_PAGE_SIZE, enablePlaceholders = false), pagingSourceFactory = { - ProfilePagingSource(api, accessToken, accountId) + ProfilePagingSource(api, accountId) } ).flow } diff --git a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/profile/ProfilePagingSource.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/profile/ProfilePagingSource.kt similarity index 64% rename from app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/profile/ProfilePagingSource.kt rename to app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/profile/ProfilePagingSource.kt index b6f6cbb4..9a98bf44 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/profile/ProfilePagingSource.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/profile/ProfilePagingSource.kt @@ -1,30 +1,31 @@ -package com.h.pixeldroid.posts.feeds.uncachedFeeds.profile +package org.pixeldroid.app.posts.feeds.uncachedFeeds.profile import androidx.paging.PagingSource import androidx.paging.PagingState -import com.h.pixeldroid.utils.api.PixelfedAPI -import com.h.pixeldroid.utils.api.objects.Status +import org.pixeldroid.app.utils.api.PixelfedAPI +import org.pixeldroid.app.utils.api.objects.Status import retrofit2.HttpException import java.io.IOException class ProfilePagingSource( private val api: PixelfedAPI, - private val accessToken: String, private val accountId: String ) : PagingSource() { override suspend fun load(params: LoadParams): LoadResult { val position = params.key return try { - val posts = api.accountPosts("Bearer $accessToken", - account_id = accountId, - max_id = position, - limit = params.loadSize + val posts = api.accountPosts( + account_id = accountId, + max_id = position, + limit = params.loadSize ) + val nextKey = posts.lastOrNull()?.id + LoadResult.Page( data = posts, prevKey = null, - nextKey = posts.lastOrNull()?.id + nextKey = if(nextKey == position) null else nextKey ) } catch (exception: HttpException) { LoadResult.Error(exception) diff --git a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/search/SearchAccountFragment.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/search/SearchAccountFragment.kt similarity index 67% rename from app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/search/SearchAccountFragment.kt rename to app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/search/SearchAccountFragment.kt index 68ace7cc..f43d3817 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/search/SearchAccountFragment.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/search/SearchAccountFragment.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.posts.feeds.uncachedFeeds.search +package org.pixeldroid.app.posts.feeds.uncachedFeeds.search import android.os.Bundle import android.view.LayoutInflater @@ -6,10 +6,10 @@ import android.view.View import android.view.ViewGroup import androidx.lifecycle.ViewModelProvider import androidx.paging.ExperimentalPagingApi -import com.h.pixeldroid.posts.feeds.uncachedFeeds.* -import com.h.pixeldroid.posts.feeds.uncachedFeeds.accountLists.AccountAdapter -import com.h.pixeldroid.utils.api.objects.Account -import com.h.pixeldroid.utils.api.objects.Results +import org.pixeldroid.app.posts.feeds.uncachedFeeds.* +import org.pixeldroid.app.posts.feeds.uncachedFeeds.accountLists.AccountAdapter +import org.pixeldroid.app.utils.api.objects.Account +import org.pixeldroid.app.utils.api.objects.Results /** * Fragment to show a list of [Account]s, as a result of a search. @@ -37,15 +37,14 @@ class SearchAccountFragment : UncachedFeedFragment() { // get the view model @Suppress("UNCHECKED_CAST") - viewModel = ViewModelProvider(this, ViewModelFactory( + viewModel = ViewModelProvider(requireActivity(), ViewModelFactory( SearchContentRepository( - apiHolder.setDomainToCurrentUser(db), + apiHolder.setToCurrentUser(), Results.SearchType.accounts, - db.userDao().getActiveUser()!!.accessToken, query ) ) - ).get(FeedViewModel::class.java) as FeedViewModel + ).get("searchAccounts", FeedViewModel::class.java) as FeedViewModel launch() initSearch() diff --git a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/search/SearchContentRepository.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/search/SearchContentRepository.kt similarity index 68% rename from app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/search/SearchContentRepository.kt rename to app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/search/SearchContentRepository.kt index e307cfb4..d4c0718e 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/search/SearchContentRepository.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/search/SearchContentRepository.kt @@ -1,13 +1,13 @@ -package com.h.pixeldroid.posts.feeds.uncachedFeeds.search +package org.pixeldroid.app.posts.feeds.uncachedFeeds.search import androidx.paging.ExperimentalPagingApi import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.PagingData -import com.h.pixeldroid.utils.api.PixelfedAPI -import com.h.pixeldroid.posts.feeds.uncachedFeeds.UncachedContentRepository -import com.h.pixeldroid.utils.api.objects.FeedContent -import com.h.pixeldroid.utils.api.objects.Results +import org.pixeldroid.app.utils.api.PixelfedAPI +import org.pixeldroid.app.posts.feeds.uncachedFeeds.UncachedContentRepository +import org.pixeldroid.app.utils.api.objects.FeedContent +import org.pixeldroid.app.utils.api.objects.Results import kotlinx.coroutines.flow.Flow import javax.inject.Inject @@ -15,14 +15,13 @@ import javax.inject.Inject * Repository class to perform searches * * The type argument [T] and the [Results.SearchType][type] argument should always - * be in agreement, e.g. if [T] is a [com.h.pixeldroid.utils.api.objects.Account] then + * be in agreement, e.g. if [T] is a [org.pixeldroid.app.utils.api.objects.Account] then * [type] should be [Results.SearchType.accounts]. */ class SearchContentRepository @ExperimentalPagingApi @Inject constructor( private val api: PixelfedAPI, private val type: Results.SearchType, - private val accessToken: String, private val query: String, ): UncachedContentRepository { override fun getStream(): Flow> { @@ -32,7 +31,7 @@ class SearchContentRepository @ExperimentalPagingApi pageSize = NETWORK_PAGE_SIZE, enablePlaceholders = false), pagingSourceFactory = { - SearchPagingSource(api, query, type, accessToken) + SearchPagingSource(api, query, type) } ).flow } diff --git a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/search/SearchHashtagFragment.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/search/SearchHashtagFragment.kt similarity index 77% rename from app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/search/SearchHashtagFragment.kt rename to app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/search/SearchHashtagFragment.kt index b59ac7d2..8eb1046c 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/search/SearchHashtagFragment.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/search/SearchHashtagFragment.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.posts.feeds.uncachedFeeds.search +package org.pixeldroid.app.posts.feeds.uncachedFeeds.search import android.annotation.SuppressLint import android.os.Bundle @@ -11,13 +11,14 @@ import androidx.paging.ExperimentalPagingApi import androidx.paging.PagingDataAdapter import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView -import com.h.pixeldroid.R -import com.h.pixeldroid.databinding.FragmentTagsBinding -import com.h.pixeldroid.posts.feeds.uncachedFeeds.FeedViewModel -import com.h.pixeldroid.posts.feeds.uncachedFeeds.UncachedFeedFragment -import com.h.pixeldroid.posts.feeds.uncachedFeeds.ViewModelFactory -import com.h.pixeldroid.utils.api.objects.Results -import com.h.pixeldroid.utils.api.objects.Tag +import org.pixeldroid.app.R +import org.pixeldroid.app.databinding.FragmentTagsBinding +import org.pixeldroid.app.posts.feeds.uncachedFeeds.FeedViewModel +import org.pixeldroid.app.posts.feeds.uncachedFeeds.UncachedFeedFragment +import org.pixeldroid.app.posts.feeds.uncachedFeeds.ViewModelFactory +import org.pixeldroid.app.utils.api.objects.Results +import org.pixeldroid.app.utils.api.objects.Tag +import org.pixeldroid.app.utils.api.objects.Tag.Companion.openTag /** * Fragment to show a list of [hashtag][Tag]s, as a result of a search. @@ -44,16 +45,15 @@ class SearchHashtagFragment : UncachedFeedFragment() { // get the view model @Suppress("UNCHECKED_CAST") - viewModel = ViewModelProvider(this, ViewModelFactory( + viewModel = ViewModelProvider(requireActivity(), ViewModelFactory( SearchContentRepository( - apiHolder.setDomainToCurrentUser(db), + apiHolder.setToCurrentUser(), Results.SearchType.hashtags, - db.userDao().getActiveUser()!!.accessToken, query ) ) ) - .get(FeedViewModel::class.java) as FeedViewModel + .get("searchHashtag", FeedViewModel::class.java) as FeedViewModel launch() initSearch() @@ -87,7 +87,7 @@ class HashTagAdapter : PagingDataAdapter( companion object { private val UIMODEL_COMPARATOR = object : DiffUtil.ItemCallback() { override fun areItemsTheSame(oldItem: Tag, newItem: Tag): Boolean { - return oldItem.id == newItem.id + return oldItem.name == newItem.name } override fun areContentsTheSame(oldItem: Tag, newItem: Tag): Boolean = @@ -108,7 +108,9 @@ class HashTagViewHolder(binding: FragmentTagsBinding) : RecyclerView.ViewHolder( init { itemView.setOnClickListener { - //TODO + tag?.apply { + openTag(itemView.context, this.name) + } } } diff --git a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/search/SearchPagingSource.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/search/SearchPagingSource.kt similarity index 66% rename from app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/search/SearchPagingSource.kt rename to app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/search/SearchPagingSource.kt index f007cf35..7c4de7ef 100644 --- a/app/src/main/java/com/h/pixeldroid/posts/feeds/uncachedFeeds/search/SearchPagingSource.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/uncachedFeeds/search/SearchPagingSource.kt @@ -1,10 +1,10 @@ -package com.h.pixeldroid.posts.feeds.uncachedFeeds.search +package org.pixeldroid.app.posts.feeds.uncachedFeeds.search import androidx.paging.PagingSource import androidx.paging.PagingState -import com.h.pixeldroid.utils.api.PixelfedAPI -import com.h.pixeldroid.utils.api.objects.FeedContent -import com.h.pixeldroid.utils.api.objects.Results +import org.pixeldroid.app.utils.api.PixelfedAPI +import org.pixeldroid.app.utils.api.objects.FeedContent +import org.pixeldroid.app.utils.api.objects.Results import retrofit2.HttpException import java.io.IOException @@ -15,16 +15,16 @@ class SearchPagingSource( private val api: PixelfedAPI, private val query: String, private val type: Results.SearchType, - private val accessToken: String, ) : PagingSource() { override suspend fun load(params: LoadParams): LoadResult { val position = params.key return try { - val response = api.search(authorization = "Bearer $accessToken", - offset = position?.toString(), - q = query, + val response = api.search( type = type, - limit = params.loadSize.toString()) + q = query, + limit = params.loadSize.toString(), + offset = position?.toString() + ) @Suppress("UNCHECKED_CAST") @@ -34,10 +34,12 @@ class SearchPagingSource( Results.SearchType.statuses -> response.statuses } as List + val nextKey = if (repos.isEmpty()) null else (position ?: 0) + repos.size + LoadResult.Page( data = repos, prevKey = null, - nextKey = if (repos.isEmpty()) null else (position ?: 0) + repos.size + nextKey = if(nextKey == position) null else nextKey ) } catch (exception: HttpException) { LoadResult.Error(exception) @@ -46,8 +48,9 @@ class SearchPagingSource( } } - override fun getRefreshKey(state: PagingState): Int? = - state.anchorPosition?.run { - state.closestItemToPosition(this)?.id?.toIntOrNull() - } + /** + * FIXME if implemented with [PagingState.anchorPosition], this breaks refreshes? How is this + * supposed to work? + */ + override fun getRefreshKey(state: PagingState): Int? = null } \ No newline at end of file diff --git a/app/src/main/java/com/h/pixeldroid/profile/FollowsActivity.kt b/app/src/main/java/org/pixeldroid/app/profile/FollowsActivity.kt similarity index 71% rename from app/src/main/java/com/h/pixeldroid/profile/FollowsActivity.kt rename to app/src/main/java/org/pixeldroid/app/profile/FollowsActivity.kt index e49c2fb2..86ffe308 100644 --- a/app/src/main/java/com/h/pixeldroid/profile/FollowsActivity.kt +++ b/app/src/main/java/org/pixeldroid/app/profile/FollowsActivity.kt @@ -1,13 +1,13 @@ -package com.h.pixeldroid.profile +package org.pixeldroid.app.profile import android.os.Bundle -import com.h.pixeldroid.R -import com.h.pixeldroid.posts.feeds.uncachedFeeds.accountLists.AccountListFragment -import com.h.pixeldroid.utils.api.objects.Account -import com.h.pixeldroid.utils.api.objects.Account.Companion.ACCOUNT_ID_TAG -import com.h.pixeldroid.utils.api.objects.Account.Companion.ACCOUNT_TAG -import com.h.pixeldroid.utils.api.objects.Account.Companion.FOLLOWERS_TAG -import com.h.pixeldroid.utils.BaseActivity +import org.pixeldroid.app.R +import org.pixeldroid.app.posts.feeds.uncachedFeeds.accountLists.AccountListFragment +import org.pixeldroid.app.utils.api.objects.Account +import org.pixeldroid.app.utils.api.objects.Account.Companion.ACCOUNT_ID_TAG +import org.pixeldroid.app.utils.api.objects.Account.Companion.ACCOUNT_TAG +import org.pixeldroid.app.utils.api.objects.Account.Companion.FOLLOWERS_TAG +import org.pixeldroid.app.utils.BaseActivity class FollowsActivity : BaseActivity() { @@ -31,11 +31,6 @@ class FollowsActivity : BaseActivity() { } } - override fun onSupportNavigateUp(): Boolean { - onBackPressed() - return true - } - private fun startFragment(id : String, displayName: String, followers : Boolean) { supportActionBar?.title = if (followers) { diff --git a/app/src/main/java/com/h/pixeldroid/profile/ProfileActivity.kt b/app/src/main/java/org/pixeldroid/app/profile/ProfileActivity.kt similarity index 77% rename from app/src/main/java/com/h/pixeldroid/profile/ProfileActivity.kt rename to app/src/main/java/org/pixeldroid/app/profile/ProfileActivity.kt index 4675e136..40520770 100644 --- a/app/src/main/java/com/h/pixeldroid/profile/ProfileActivity.kt +++ b/app/src/main/java/org/pixeldroid/app/profile/ProfileActivity.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.profile +package org.pixeldroid.app.profile import android.content.Intent import android.os.Bundle @@ -7,6 +7,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.* +import androidx.appcompat.app.AlertDialog import androidx.appcompat.content.res.AppCompatResources import androidx.core.content.ContextCompat import androidx.lifecycle.ViewModel @@ -18,34 +19,31 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import com.google.android.material.snackbar.Snackbar -import com.h.pixeldroid.R -import com.h.pixeldroid.databinding.ActivityProfileBinding -import com.h.pixeldroid.databinding.FragmentProfilePostsBinding -import com.h.pixeldroid.posts.PostActivity -import com.h.pixeldroid.posts.feeds.initAdapter -import com.h.pixeldroid.posts.feeds.launch -import com.h.pixeldroid.posts.feeds.uncachedFeeds.FeedViewModel -import com.h.pixeldroid.posts.feeds.uncachedFeeds.UncachedContentRepository -import com.h.pixeldroid.posts.feeds.uncachedFeeds.profile.ProfileContentRepository -import com.h.pixeldroid.posts.parseHTMLText -import com.h.pixeldroid.utils.BaseActivity -import com.h.pixeldroid.utils.ImageConverter -import com.h.pixeldroid.utils.api.PixelfedAPI -import com.h.pixeldroid.utils.api.objects.Account -import com.h.pixeldroid.utils.api.objects.FeedContent -import com.h.pixeldroid.utils.api.objects.Status -import com.h.pixeldroid.utils.db.entities.UserDatabaseEntity -import com.h.pixeldroid.utils.openUrl +import org.pixeldroid.app.R +import org.pixeldroid.app.databinding.ActivityProfileBinding +import org.pixeldroid.app.databinding.FragmentProfilePostsBinding +import org.pixeldroid.app.posts.PostActivity +import org.pixeldroid.app.posts.feeds.initAdapter +import org.pixeldroid.app.posts.feeds.launch +import org.pixeldroid.app.posts.feeds.uncachedFeeds.FeedViewModel +import org.pixeldroid.app.posts.feeds.uncachedFeeds.UncachedContentRepository +import org.pixeldroid.app.posts.feeds.uncachedFeeds.profile.ProfileContentRepository +import org.pixeldroid.app.posts.parseHTMLText +import org.pixeldroid.app.utils.BaseActivity +import org.pixeldroid.app.utils.ImageConverter +import org.pixeldroid.app.utils.api.PixelfedAPI +import org.pixeldroid.app.utils.api.objects.Account +import org.pixeldroid.app.utils.api.objects.FeedContent +import org.pixeldroid.app.utils.api.objects.Status +import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity +import org.pixeldroid.app.utils.openUrl import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch import retrofit2.HttpException import java.io.IOException class ProfileActivity : BaseActivity() { - private lateinit var pixelfedAPI : PixelfedAPI - private lateinit var accessToken : String private lateinit var domain : String private lateinit var accountId : String private lateinit var binding: ActivityProfileBinding @@ -66,8 +64,6 @@ class ProfileActivity : BaseActivity() { user = db.userDao().getActiveUser() domain = user?.instance_uri.orEmpty() - pixelfedAPI = apiHolder.api ?: apiHolder.setDomainToCurrentUser(db) - accessToken = user?.accessToken.orEmpty() // Set profile according to given account val account = intent.getSerializableExtra(Account.ACCOUNT_TAG) as Account? @@ -77,9 +73,8 @@ class ProfileActivity : BaseActivity() { @Suppress("UNCHECKED_CAST") viewModel = ViewModelProvider(this, ProfileViewModelFactory( ProfileContentRepository( - apiHolder.setDomainToCurrentUser(db), - db.userDao().getActiveUser()!!.accessToken, - accountId + apiHolder.setToCurrentUser(), + accountId ) ) ).get(FeedViewModel::class.java) as FeedViewModel @@ -96,9 +91,7 @@ class ProfileActivity : BaseActivity() { } setContent(account) - @Suppress("UNCHECKED_CAST") - job = launch(job, lifecycleScope, viewModel as FeedViewModel, - profileAdapter as PagingDataAdapter) + job = launch(job, lifecycleScope, viewModel, profileAdapter) } /** @@ -114,18 +107,14 @@ class ProfileActivity : BaseActivity() { binding.profileRefreshLayout.isRefreshing = false } - override fun onSupportNavigateUp(): Boolean { - onBackPressed() - return true - } - private fun setContent(account: Account?) { if(account != null) { setViews(account) } else { lifecycleScope.launchWhenResumed { + val api: PixelfedAPI = apiHolder.api ?: apiHolder.setToCurrentUser() val myAccount: Account = try { - pixelfedAPI.verifyCredentials("Bearer $accessToken") + api.verifyCredentials() } catch (exception: IOException) { Log.e("ProfileActivity:", exception.toString()) return@launchWhenResumed showError() @@ -162,9 +151,9 @@ class ProfileActivity : BaseActivity() { ) binding.descriptionTextView.text = parseHTMLText( - account.note ?: "", emptyList(), pixelfedAPI, - applicationContext, "Bearer $accessToken", - lifecycleScope + account.note ?: "", emptyList(), apiHolder, + applicationContext, + lifecycleScope ) val displayName = account.getusername() @@ -235,13 +224,14 @@ class ProfileActivity : BaseActivity() { // Get relationship between the two users (credential and this) and set followButton accordingly lifecycleScope.launch { try { - val relationship = pixelfedAPI.checkRelationships( - "Bearer $accessToken", listOf(account.id.orEmpty()) + val api: PixelfedAPI = apiHolder.api ?: apiHolder.setToCurrentUser() + val relationship = api.checkRelationships( + listOf(account.id.orEmpty()) ).firstOrNull() if(relationship != null){ - if (relationship.following) { - setOnClickUnfollow(account) + if (relationship.following == true || relationship.requested == true) { + setOnClickUnfollow(account, relationship.requested == true) } else { setOnClickFollow(account) } @@ -268,8 +258,10 @@ class ProfileActivity : BaseActivity() { setOnClickListener { lifecycleScope.launchWhenResumed { try { - pixelfedAPI.follow(account.id.orEmpty(), "Bearer $accessToken") - setOnClickUnfollow(account) + val api: PixelfedAPI = apiHolder.api ?: apiHolder.setToCurrentUser() + val rel = api.follow(account.id.orEmpty()) + if(rel.following == true) setOnClickUnfollow(account, rel.requested == true) + else setOnClickFollow(account) } catch (exception: IOException) { Log.e("FOLLOW ERROR", exception.toString()) Toast.makeText( @@ -287,29 +279,46 @@ class ProfileActivity : BaseActivity() { } } - private fun setOnClickUnfollow(account: Account) { + private fun setOnClickUnfollow(account: Account, requested: Boolean) { binding.followButton.apply { - setText(R.string.unfollow) + if(account.locked == true && requested) { + setText(R.string.follow_requested) + } else setText(R.string.unfollow) - setOnClickListener { + + fun unfollow() { lifecycleScope.launchWhenResumed { try { - pixelfedAPI.unfollow(account.id.orEmpty(), "Bearer $accessToken") - setOnClickFollow(account) + val api: PixelfedAPI = apiHolder.api ?: apiHolder.setToCurrentUser() + val rel = api.unfollow(account.id.orEmpty()) + if(rel.following == false && rel.requested == false) setOnClickFollow(account) + else setOnClickUnfollow(account, rel.requested == true) } catch (exception: IOException) { Log.e("FOLLOW ERROR", exception.toString()) Toast.makeText( - applicationContext, getString(R.string.unfollow_error), - Toast.LENGTH_SHORT + applicationContext, getString(R.string.unfollow_error), + Toast.LENGTH_SHORT ).show() } catch (exception: HttpException) { Toast.makeText( - applicationContext, getString(R.string.unfollow_error), - Toast.LENGTH_SHORT + applicationContext, getString(R.string.unfollow_error), + Toast.LENGTH_SHORT ).show() } } } + + setOnClickListener { + if(account.locked == true && requested){ + AlertDialog.Builder(context) + .setMessage(R.string.dialog_message_cancel_follow_request) + .setPositiveButton(android.R.string.ok) { _, _ -> + unfollow() + } + .setNegativeButton(android.R.string.cancel){_, _ -> } + .show() + } else unfollow() + } } } } diff --git a/app/src/main/java/com/h/pixeldroid/profile/ProfilePostsRecyclerViewAdapter.kt b/app/src/main/java/org/pixeldroid/app/profile/ProfilePostsRecyclerViewAdapter.kt similarity index 86% rename from app/src/main/java/com/h/pixeldroid/profile/ProfilePostsRecyclerViewAdapter.kt rename to app/src/main/java/org/pixeldroid/app/profile/ProfilePostsRecyclerViewAdapter.kt index ce9a8d6e..bd3b6e51 100644 --- a/app/src/main/java/com/h/pixeldroid/profile/ProfilePostsRecyclerViewAdapter.kt +++ b/app/src/main/java/org/pixeldroid/app/profile/ProfilePostsRecyclerViewAdapter.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.profile +package org.pixeldroid.app.profile import android.content.Intent import android.view.LayoutInflater @@ -7,11 +7,11 @@ import android.view.ViewGroup import android.widget.ImageView import androidx.appcompat.content.res.AppCompatResources.getDrawable import androidx.recyclerview.widget.RecyclerView -import com.h.pixeldroid.posts.PostActivity -import com.h.pixeldroid.R -import com.h.pixeldroid.utils.api.objects.Status -import com.h.pixeldroid.utils.ImageConverter.Companion.setSquareImageFromDrawable -import com.h.pixeldroid.utils.ImageConverter.Companion.setSquareImageFromURL +import org.pixeldroid.app.posts.PostActivity +import org.pixeldroid.app.R +import org.pixeldroid.app.utils.api.objects.Status +import org.pixeldroid.app.utils.ImageConverter.Companion.setSquareImageFromDrawable +import org.pixeldroid.app.utils.ImageConverter.Companion.setSquareImageFromURL /** * [RecyclerView.Adapter] that can display a list of [Status]s diff --git a/app/src/main/java/com/h/pixeldroid/searchDiscover/SearchActivity.kt b/app/src/main/java/org/pixeldroid/app/searchDiscover/SearchActivity.kt similarity index 84% rename from app/src/main/java/com/h/pixeldroid/searchDiscover/SearchActivity.kt rename to app/src/main/java/org/pixeldroid/app/searchDiscover/SearchActivity.kt index f55c8d6b..15825383 100644 --- a/app/src/main/java/com/h/pixeldroid/searchDiscover/SearchActivity.kt +++ b/app/src/main/java/org/pixeldroid/app/searchDiscover/SearchActivity.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.searchDiscover +package org.pixeldroid.app.searchDiscover import android.app.SearchManager import android.content.Intent @@ -8,12 +8,12 @@ import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.widget.ViewPager2 import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayoutMediator -import com.h.pixeldroid.R -import com.h.pixeldroid.posts.feeds.uncachedFeeds.search.SearchAccountFragment -import com.h.pixeldroid.posts.feeds.uncachedFeeds.search.SearchHashtagFragment -import com.h.pixeldroid.posts.feeds.uncachedFeeds.search.SearchPostsFragment -import com.h.pixeldroid.utils.api.objects.Results -import com.h.pixeldroid.utils.BaseActivity +import org.pixeldroid.app.R +import org.pixeldroid.app.posts.feeds.uncachedFeeds.UncachedPostsFragment +import org.pixeldroid.app.posts.feeds.uncachedFeeds.search.SearchAccountFragment +import org.pixeldroid.app.posts.feeds.uncachedFeeds.search.SearchHashtagFragment +import org.pixeldroid.app.utils.api.objects.Results +import org.pixeldroid.app.utils.BaseActivity class SearchActivity : BaseActivity() { @@ -47,14 +47,9 @@ class SearchActivity : BaseActivity() { setupTabs(tabs, searchType) } - override fun onSupportNavigateUp(): Boolean { - onBackPressed() - return true - } - private fun createSearchTabs(query: String): Array{ - val searchFeedFragment = SearchPostsFragment() + val searchFeedFragment = UncachedPostsFragment() val searchAccountListFragment = SearchAccountFragment() val searchHashtagFragment: Fragment = SearchHashtagFragment() diff --git a/app/src/main/java/com/h/pixeldroid/searchDiscover/SearchDiscoverFragment.kt b/app/src/main/java/org/pixeldroid/app/searchDiscover/SearchDiscoverFragment.kt similarity index 76% rename from app/src/main/java/com/h/pixeldroid/searchDiscover/SearchDiscoverFragment.kt rename to app/src/main/java/org/pixeldroid/app/searchDiscover/SearchDiscoverFragment.kt index 2226de69..31dfb11d 100644 --- a/app/src/main/java/com/h/pixeldroid/searchDiscover/SearchDiscoverFragment.kt +++ b/app/src/main/java/org/pixeldroid/app/searchDiscover/SearchDiscoverFragment.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.searchDiscover +package org.pixeldroid.app.searchDiscover import android.app.SearchManager import android.content.Context @@ -11,21 +11,15 @@ import androidx.annotation.StringRes import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView -import com.h.pixeldroid.R -import com.h.pixeldroid.databinding.FragmentSearchBinding -import com.h.pixeldroid.profile.ProfilePostViewHolder -import com.h.pixeldroid.utils.api.PixelfedAPI -import com.h.pixeldroid.utils.api.objects.Status -import com.h.pixeldroid.posts.PostActivity -import com.h.pixeldroid.utils.BaseFragment -import com.h.pixeldroid.utils.ImageConverter -import com.h.pixeldroid.utils.bindingLifecycleAware -import com.mikepenz.iconics.IconicsColor -import com.mikepenz.iconics.IconicsDrawable -import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial -import com.mikepenz.iconics.utils.color -import com.mikepenz.iconics.utils.paddingDp -import com.mikepenz.iconics.utils.sizeDp +import org.pixeldroid.app.R +import org.pixeldroid.app.databinding.FragmentSearchBinding +import org.pixeldroid.app.profile.ProfilePostViewHolder +import org.pixeldroid.app.utils.api.PixelfedAPI +import org.pixeldroid.app.utils.api.objects.Status +import org.pixeldroid.app.posts.PostActivity +import org.pixeldroid.app.utils.BaseFragment +import org.pixeldroid.app.utils.ImageConverter +import org.pixeldroid.app.utils.bindingLifecycleAware import retrofit2.HttpException import java.io.IOException @@ -37,7 +31,6 @@ class SearchDiscoverFragment : BaseFragment() { private lateinit var api: PixelfedAPI private lateinit var recycler : RecyclerView private lateinit var adapter : DiscoverRecyclerViewAdapter - private lateinit var accessToken: String var binding: FragmentSearchBinding by bindingLifecycleAware() @@ -66,9 +59,7 @@ class SearchDiscoverFragment : BaseFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - api = apiHolder.api ?: apiHolder.setDomainToCurrentUser(db) - - accessToken = db.userDao().getActiveUser()?.accessToken.orEmpty() + api = apiHolder.api ?: apiHolder.setToCurrentUser() getDiscover() @@ -93,8 +84,9 @@ class SearchDiscoverFragment : BaseFragment() { private fun getDiscover() { lifecycleScope.launchWhenCreated { try { - val discoverPosts = api.discover("Bearer $accessToken") + val discoverPosts = api.discover() adapter.addPosts(discoverPosts.posts) + binding.discoverNoInfiniteLoad.visibility = View.VISIBLE showError(show = false) } catch (exception: IOException) { showError() @@ -108,7 +100,7 @@ class SearchDiscoverFragment : BaseFragment() { * [RecyclerView.Adapter] that can display a list of [Status]s' thumbnails for the discover view */ class DiscoverRecyclerViewAdapter: RecyclerView.Adapter() { - private val posts: ArrayList = ArrayList() + private val posts: ArrayList = ArrayList() fun addPosts(newPosts : List) { posts.clear() @@ -124,12 +116,12 @@ class SearchDiscoverFragment : BaseFragment() { override fun onBindViewHolder(holder: ProfilePostViewHolder, position: Int) { val post = posts[position] - if(post.media_attachments?.size ?: 0 > 1) { + if(post?.media_attachments?.size ?: 0 > 1) { holder.albumIcon.visibility = View.VISIBLE } else { holder.albumIcon.visibility = View.GONE } - ImageConverter.setSquareImageFromURL(holder.postView, post.media_attachments?.firstOrNull()?.preview_url, holder.postPreview, post.media_attachments?.firstOrNull()?.blurhash) + ImageConverter.setSquareImageFromURL(holder.postView, post?.media_attachments?.firstOrNull()?.preview_url, holder.postPreview, post?.media_attachments?.firstOrNull()?.blurhash) holder.postPreview.setOnClickListener { val intent = Intent(holder.postView.context, PostActivity::class.java) intent.putExtra(Status.POST_TAG, post) diff --git a/app/src/main/java/com/h/pixeldroid/settings/AboutActivity.kt b/app/src/main/java/org/pixeldroid/app/settings/AboutActivity.kt similarity index 76% rename from app/src/main/java/com/h/pixeldroid/settings/AboutActivity.kt rename to app/src/main/java/org/pixeldroid/app/settings/AboutActivity.kt index 2532186c..f4353a78 100644 --- a/app/src/main/java/com/h/pixeldroid/settings/AboutActivity.kt +++ b/app/src/main/java/org/pixeldroid/app/settings/AboutActivity.kt @@ -1,11 +1,11 @@ -package com.h.pixeldroid.settings +package org.pixeldroid.app.settings import android.content.Intent import android.os.Bundle -import com.h.pixeldroid.BuildConfig -import com.h.pixeldroid.R -import com.h.pixeldroid.databinding.ActivityAboutBinding -import com.h.pixeldroid.utils.BaseActivity +import org.pixeldroid.app.BuildConfig +import org.pixeldroid.app.R +import org.pixeldroid.app.databinding.ActivityAboutBinding +import org.pixeldroid.app.utils.BaseActivity class AboutActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { diff --git a/app/src/main/java/com/h/pixeldroid/settings/LicenseActivity.kt b/app/src/main/java/org/pixeldroid/app/settings/LicenseActivity.kt similarity index 73% rename from app/src/main/java/com/h/pixeldroid/settings/LicenseActivity.kt rename to app/src/main/java/org/pixeldroid/app/settings/LicenseActivity.kt index 5394b267..dc272dad 100644 --- a/app/src/main/java/com/h/pixeldroid/settings/LicenseActivity.kt +++ b/app/src/main/java/org/pixeldroid/app/settings/LicenseActivity.kt @@ -1,9 +1,9 @@ -package com.h.pixeldroid.settings +package org.pixeldroid.app.settings import android.os.Bundle -import com.h.pixeldroid.R -import com.h.pixeldroid.databinding.ActivityLicensesBinding -import com.h.pixeldroid.utils.BaseActivity +import org.pixeldroid.app.R +import org.pixeldroid.app.databinding.ActivityLicensesBinding +import org.pixeldroid.app.utils.BaseActivity class LicenseActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { diff --git a/app/src/main/java/com/h/pixeldroid/settings/SettingsActivity.kt b/app/src/main/java/org/pixeldroid/app/settings/SettingsActivity.kt similarity index 92% rename from app/src/main/java/com/h/pixeldroid/settings/SettingsActivity.kt rename to app/src/main/java/org/pixeldroid/app/settings/SettingsActivity.kt index feeed674..bc005412 100644 --- a/app/src/main/java/com/h/pixeldroid/settings/SettingsActivity.kt +++ b/app/src/main/java/org/pixeldroid/app/settings/SettingsActivity.kt @@ -1,14 +1,14 @@ -package com.h.pixeldroid.settings +package org.pixeldroid.app.settings import android.content.Intent import android.content.SharedPreferences import android.os.Bundle import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceManager -import com.h.pixeldroid.MainActivity -import com.h.pixeldroid.R -import com.h.pixeldroid.utils.BaseActivity -import com.h.pixeldroid.utils.setThemeFromPreferences +import org.pixeldroid.app.MainActivity +import org.pixeldroid.app.R +import org.pixeldroid.app.utils.BaseActivity +import org.pixeldroid.app.utils.setThemeFromPreferences class SettingsActivity : BaseActivity(), SharedPreferences.OnSharedPreferenceChangeListener { private var restartMainOnExit = false diff --git a/app/src/main/java/com/h/pixeldroid/utils/BaseActivity.kt b/app/src/main/java/org/pixeldroid/app/utils/BaseActivity.kt similarity index 89% rename from app/src/main/java/com/h/pixeldroid/utils/BaseActivity.kt rename to app/src/main/java/org/pixeldroid/app/utils/BaseActivity.kt index 61f4b358..87c5ed98 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/BaseActivity.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/BaseActivity.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.utils +package org.pixeldroid.app.utils import android.content.Context import android.content.res.Configuration @@ -7,8 +7,8 @@ import android.os.Build import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.preference.PreferenceManager -import com.h.pixeldroid.utils.db.AppDatabase -import com.h.pixeldroid.utils.di.PixelfedAPIHolder +import org.pixeldroid.app.utils.db.AppDatabase +import org.pixeldroid.app.utils.di.PixelfedAPIHolder import java.util.* import javax.inject.Inject @@ -28,6 +28,11 @@ open class BaseActivity : AppCompatActivity() { super.attachBaseContext(updateBaseContextLocale(base)) } + override fun onSupportNavigateUp(): Boolean { + onBackPressed() + return true + } + private fun updateBaseContextLocale(context: Context): Context { val language = PreferenceManager.getDefaultSharedPreferences(context).getString("language", "default") ?: "default" if(language == "default"){ diff --git a/app/src/main/java/com/h/pixeldroid/utils/BaseFragment.kt b/app/src/main/java/org/pixeldroid/app/utils/BaseFragment.kt similarity index 80% rename from app/src/main/java/com/h/pixeldroid/utils/BaseFragment.kt rename to app/src/main/java/org/pixeldroid/app/utils/BaseFragment.kt index bb42777f..edac820a 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/BaseFragment.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/BaseFragment.kt @@ -1,9 +1,9 @@ -package com.h.pixeldroid.utils +package org.pixeldroid.app.utils import android.os.Bundle import androidx.fragment.app.Fragment -import com.h.pixeldroid.utils.db.AppDatabase -import com.h.pixeldroid.utils.di.PixelfedAPIHolder +import org.pixeldroid.app.utils.db.AppDatabase +import org.pixeldroid.app.utils.di.PixelfedAPIHolder import javax.inject.Inject /** diff --git a/app/src/main/java/com/h/pixeldroid/utils/BlurHashDecoder.kt b/app/src/main/java/org/pixeldroid/app/utils/BlurHashDecoder.kt similarity index 98% rename from app/src/main/java/com/h/pixeldroid/utils/BlurHashDecoder.kt rename to app/src/main/java/org/pixeldroid/app/utils/BlurHashDecoder.kt index 847edc45..d45cb367 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/BlurHashDecoder.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/BlurHashDecoder.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.utils +package org.pixeldroid.app.utils /** * Blurhash implementation from blurhash project: @@ -11,7 +11,6 @@ import android.content.res.Resources import android.graphics.Bitmap import android.graphics.Color import android.graphics.drawable.BitmapDrawable -import com.h.pixeldroid.utils.api.objects.Attachment import kotlin.math.PI import kotlin.math.cos import kotlin.math.pow diff --git a/app/src/main/java/com/h/pixeldroid/utils/ImageConverter.kt b/app/src/main/java/org/pixeldroid/app/utils/ImageConverter.kt similarity index 98% rename from app/src/main/java/com/h/pixeldroid/utils/ImageConverter.kt rename to app/src/main/java/org/pixeldroid/app/utils/ImageConverter.kt index 305e4196..ce8dca05 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/ImageConverter.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/ImageConverter.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.utils +package org.pixeldroid.app.utils import android.graphics.drawable.Drawable import android.view.View @@ -8,7 +8,7 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import com.bumptech.glide.Glide import com.bumptech.glide.request.RequestOptions -import com.h.pixeldroid.R +import org.pixeldroid.app.R class ImageConverter { companion object { diff --git a/app/src/main/java/com/h/pixeldroid/utils/PixelDroidApplication.kt b/app/src/main/java/org/pixeldroid/app/utils/PixelDroidApplication.kt similarity index 83% rename from app/src/main/java/com/h/pixeldroid/utils/PixelDroidApplication.kt rename to app/src/main/java/org/pixeldroid/app/utils/PixelDroidApplication.kt index abedc1fa..0bc5c4cc 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/PixelDroidApplication.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/PixelDroidApplication.kt @@ -1,11 +1,10 @@ -package com.h.pixeldroid.utils +package org.pixeldroid.app.utils import android.app.Application import androidx.preference.PreferenceManager -import com.h.pixeldroid.utils.di.* +import org.pixeldroid.app.utils.di.* import com.mikepenz.iconics.Iconics import org.ligi.tracedroid.TraceDroid -import org.ligi.tracedroid.sending.sendTraceDroidStackTracesIfExist class PixelDroidApplication: Application() { @@ -27,8 +26,6 @@ class PixelDroidApplication: Application() { .aPIModule(APIModule()) .build() mApplicationComponent.inject(this) - - Iconics.init(applicationContext) } fun getAppComponent(): ApplicationComponent { diff --git a/app/src/main/java/com/h/pixeldroid/utils/Utils.kt b/app/src/main/java/org/pixeldroid/app/utils/Utils.kt similarity index 80% rename from app/src/main/java/com/h/pixeldroid/utils/Utils.kt rename to app/src/main/java/org/pixeldroid/app/utils/Utils.kt index 2431574b..8769881b 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/Utils.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/Utils.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.utils +package org.pixeldroid.app.utils import android.content.ActivityNotFoundException import android.content.Context @@ -15,7 +15,9 @@ import androidx.browser.customtabs.CustomTabsIntent import androidx.fragment.app.Fragment import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.LifecycleOwner -import com.h.pixeldroid.R +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import org.pixeldroid.app.R import okhttp3.HttpUrl import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty @@ -79,6 +81,29 @@ fun BaseActivity.openUrl(url: String): Boolean{ } } + +fun RecyclerView.limitedLengthSmoothScrollToPosition(targetItem: Int) { + layoutManager?.apply { + val maxScroll = 3 + when (this) { + is LinearLayoutManager -> { + val topItem = findFirstVisibleItemPosition() + val distance = topItem - targetItem + val anchorItem = when { + distance > maxScroll -> targetItem + maxScroll + distance < -maxScroll -> targetItem - maxScroll + else -> topItem + } + if (anchorItem != topItem) scrollToPosition(anchorItem) + post { + smoothScrollToPosition(targetItem) + } + } + else -> smoothScrollToPosition(targetItem) + } + } +} + /** * @brief Updates the application's theme depending on the given preferences and resources */ diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/PixelfedAPI.kt b/app/src/main/java/org/pixeldroid/app/utils/api/PixelfedAPI.kt similarity index 80% rename from app/src/main/java/com/h/pixeldroid/utils/api/PixelfedAPI.kt rename to app/src/main/java/org/pixeldroid/app/utils/api/PixelfedAPI.kt index f4d4d188..f1e75801 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/api/PixelfedAPI.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/api/PixelfedAPI.kt @@ -1,6 +1,6 @@ -package com.h.pixeldroid.utils.api +package org.pixeldroid.app.utils.api -import com.h.pixeldroid.utils.api.objects.* +import org.pixeldroid.app.utils.api.objects.* import io.reactivex.Observable import okhttp3.MultipartBody import retrofit2.Response @@ -74,31 +74,23 @@ interface PixelfedAPI { @FormUrlEncoded @POST("/api/v1/accounts/{id}/follow") suspend fun follow( - //The authorization header needs to be of the form "Bearer " @Path("id") statusId: String, - @Header("Authorization") authorization: String, @Field("reblogs") reblogs : Boolean = true ) : Relationship @POST("/api/v1/accounts/{id}/unfollow") suspend fun unfollow( - //The authorization header needs to be of the form "Bearer " @Path("id") statusId: String, - @Header("Authorization") authorization: String ) : Relationship @POST("api/v1/statuses/{id}/favourite") suspend fun likePost( - //The authorization header needs to be of the form "Bearer " - @Header("Authorization") authorization: String, @Path("id") statusId: String ) : Status @POST("/api/v1/statuses/{id}/unfavourite") suspend fun unlikePost( - //The authorization header needs to be of the form "Bearer " - @Header("Authorization") authorization: String, @Path("id") statusId: String ) : Status @@ -106,8 +98,6 @@ interface PixelfedAPI { @FormUrlEncoded @POST("/api/v1/statuses") suspend fun postStatus( - //The authorization header needs to be of the form "Bearer " - @Header("Authorization") authorization: String, @Field("status") statusText : String, @Field("in_reply_to_id") in_reply_to_id : String? = null, @Field("media_ids[]") media_ids : List = emptyList(), @@ -124,14 +114,12 @@ interface PixelfedAPI { @DELETE("/api/v1/statuses/{id}") suspend fun deleteStatus( - @Header("Authorization") authorization: String, @Path("id") statusId: String ) @FormUrlEncoded @POST("/api/v1/statuses/{id}/reblog") suspend fun reblogStatus( - @Header("Authorization") authorization: String, @Path("id") statusId: String, @Field("visibility") visibility: String? = null ) : Status @@ -139,14 +127,12 @@ interface PixelfedAPI { @POST("/api/v1/statuses/{id}/unreblog") suspend fun undoReblogStatus( @Path("id") statusId: String, - @Header("Authorization") authorization: String ) : Status //Used in our case to retrieve comments for a given status @GET("/api/v1/statuses/{id}/context") suspend fun statusComments( @Path("id") statusId: String, - @Header("Authorization") authorization: String? = null ) : Context @GET("/api/v1/timelines/public") @@ -160,8 +146,6 @@ interface PixelfedAPI { @GET("/api/v1/timelines/home") suspend fun timelineHome( - //The authorization header needs to be of the form "Bearer " - @Header("Authorization") authorization: String, @Query("max_id") max_id: String? = null, @Query("since_id") since_id: String? = null, @Query("min_id") min_id: String? = null, @@ -169,10 +153,19 @@ interface PixelfedAPI { @Query("local") local: Boolean? = null ): List + @GET("/api/v1/timelines/tag/{hashtag}") + suspend fun hashtag( + @Path("hashtag") hashtag: String? = null, + @Query("local") local: Boolean? = null, + @Query("only_media") only_media: Boolean? = null, + @Query("max_id") max_id: String? = null, + @Query("since_id") since_id: String? = null, + @Query("min_id") min_id: String? = null, + @Query("limit") limit: Int? = null, + ): List + @GET("/api/v2/search") suspend fun search( - //The authorization header needs to be of the form "Bearer " - @Header("Authorization") authorization: String, @Query("account_id") account_id: String? = null, @Query("max_id") max_id: String? = null, @Query("min_id") min_id: String? = null, @@ -187,8 +180,6 @@ interface PixelfedAPI { @GET("/api/v1/notifications") suspend fun notifications( - //The authorization header needs to be of the form "Bearer " - @Header("Authorization") authorization: String, @Query("max_id") max_id: String? = null, @Query("since_id") since_id: String? = null, @Query("min_id") min_id: String? = null, @@ -200,13 +191,12 @@ interface PixelfedAPI { @GET("/api/v1/accounts/verify_credentials") suspend fun verifyCredentials( //The authorization header needs to be of the form "Bearer " - @Header("Authorization") authorization: String + @Header("Authorization") authorization: String? = null ): Account @GET("/api/v1/accounts/{id}/statuses") suspend fun accountPosts( - @Header("Authorization") authorization: String, @Path("id") account_id: String, @Query("min_id") min_id: String? = null, @Query("max_id") max_id: String?, @@ -215,14 +205,12 @@ interface PixelfedAPI { @GET("/api/v1/accounts/relationships") suspend fun checkRelationships( - @Header("Authorization") authorization : String, @Query("id[]") account_ids : List ) : List @GET("/api/v1/accounts/{id}/followers") suspend fun followers( @Path("id") account_id: String, - @Header("Authorization") authorization: String, @Query("max_id") max_id: String? = null, @Query("since_id") since_id: String? = null, @Query("limit") limit: Number? = null, @@ -232,7 +220,6 @@ interface PixelfedAPI { @GET("/api/v1/accounts/{id}/following") suspend fun following( @Path("id") account_id: String, - @Header("Authorization") authorization: String, @Query("max_id") max_id: String? = null, @Query("since_id") since_id: String? = null, @Query("limit") limit: Number? = 40, @@ -241,36 +228,29 @@ interface PixelfedAPI { @GET("/api/v1/accounts/{id}") suspend fun getAccount( - @Header("Authorization") authorization: String, @Path("id") accountId : String ): Account @GET("/api/v1/statuses/{id}") suspend fun getStatus( - @Header("Authorization") authorization: String, @Path("id") accountId : String ): Status @Multipart @POST("/api/v1/media") fun mediaUpload( - //The authorization header needs to be of the form "Bearer " - @Header("Authorization") authorization: String, @Part description: MultipartBody.Part? = null, @Part file: MultipartBody.Part ): Observable // get discover @GET("/api/v2/discover/posts") - suspend fun discover( - @Header("Authorization") authorization: String - ) : DiscoverPosts + suspend fun discover() : DiscoverPosts @FormUrlEncoded @POST("/api/v1/reports") @JvmSuppressWildcards suspend fun report( - @Header("Authorization") authorization: String, @Field("account_id") account_id: String, @Field("status_ids") status_ids: List, @Field("comment") comment: String, diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Account.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Account.kt similarity index 86% rename from app/src/main/java/com/h/pixeldroid/utils/api/objects/Account.kt rename to app/src/main/java/org/pixeldroid/app/utils/api/objects/Account.kt index 6f279f3f..1db5ee87 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Account.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Account.kt @@ -1,18 +1,12 @@ -package com.h.pixeldroid.utils.api.objects +package org.pixeldroid.app.utils.api.objects import android.content.Context import android.content.Intent import android.util.Log import androidx.core.content.ContextCompat.startActivity -import com.h.pixeldroid.profile.ProfileActivity -import com.h.pixeldroid.utils.api.PixelfedAPI -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.supervisorScope -import retrofit2.Call -import retrofit2.Callback +import org.pixeldroid.app.profile.ProfileActivity +import org.pixeldroid.app.utils.api.PixelfedAPI import retrofit2.HttpException -import retrofit2.Response import java.io.IOException import java.io.Serializable @@ -57,9 +51,9 @@ data class Account( /** * @brief Opens an activity of the profile with the given id */ - suspend fun openAccountFromId(id: String, api : PixelfedAPI, context: Context, credential: String) { + suspend fun openAccountFromId(id: String, api : PixelfedAPI, context: Context) { val account = try { - api.getAccount(credential, id) + api.getAccount(id) } catch (exception: IOException) { Log.e("GET ACCOUNT ERROR", exception.toString()) return diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Application.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Application.kt similarity index 87% rename from app/src/main/java/com/h/pixeldroid/utils/api/objects/Application.kt rename to app/src/main/java/org/pixeldroid/app/utils/api/objects/Application.kt index 7ee2aed6..a54374c3 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Application.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Application.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.utils.api.objects +package org.pixeldroid.app.utils.api.objects import java.io.Serializable diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Attachment.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Attachment.kt similarity index 95% rename from app/src/main/java/com/h/pixeldroid/utils/api/objects/Attachment.kt rename to app/src/main/java/org/pixeldroid/app/utils/api/objects/Attachment.kt index 1202f338..610af953 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Attachment.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Attachment.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.utils.api.objects +package org.pixeldroid.app.utils.api.objects import java.io.Serializable diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Card.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Card.kt similarity index 93% rename from app/src/main/java/com/h/pixeldroid/utils/api/objects/Card.kt rename to app/src/main/java/org/pixeldroid/app/utils/api/objects/Card.kt index 32b2cc56..6ddc6ee7 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Card.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Card.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.utils.api.objects +package org.pixeldroid.app.utils.api.objects import java.io.Serializable diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Context.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Context.kt similarity index 65% rename from app/src/main/java/com/h/pixeldroid/utils/api/objects/Context.kt rename to app/src/main/java/org/pixeldroid/app/utils/api/objects/Context.kt index 244564fe..a36200c2 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Context.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Context.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.utils.api.objects +package org.pixeldroid.app.utils.api.objects import java.io.Serializable diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/DiscoverPosts.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/DiscoverPosts.kt similarity index 73% rename from app/src/main/java/com/h/pixeldroid/utils/api/objects/DiscoverPosts.kt rename to app/src/main/java/org/pixeldroid/app/utils/api/objects/DiscoverPosts.kt index cf3c27f6..b8c82135 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/DiscoverPosts.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/DiscoverPosts.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.utils.api.objects +package org.pixeldroid.app.utils.api.objects import java.io.Serializable diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Emoji.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Emoji.kt similarity index 85% rename from app/src/main/java/com/h/pixeldroid/utils/api/objects/Emoji.kt rename to app/src/main/java/org/pixeldroid/app/utils/api/objects/Emoji.kt index f1116e55..4a9197dd 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Emoji.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Emoji.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.utils.api.objects +package org.pixeldroid.app.utils.api.objects import java.io.Serializable diff --git a/app/src/main/java/org/pixeldroid/app/utils/api/objects/Error.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Error.kt new file mode 100644 index 00000000..d4ab68e5 --- /dev/null +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Error.kt @@ -0,0 +1,7 @@ +package org.pixeldroid.app.utils.api.objects + +import java.io.Serializable + +data class Error( + val error: String? +): Serializable \ No newline at end of file diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/FeedContent.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/FeedContent.kt similarity index 77% rename from app/src/main/java/com/h/pixeldroid/utils/api/objects/FeedContent.kt rename to app/src/main/java/org/pixeldroid/app/utils/api/objects/FeedContent.kt index 80ed4403..e9e188fb 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/FeedContent.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/FeedContent.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.utils.api.objects +package org.pixeldroid.app.utils.api.objects interface FeedContent { val id: String? diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Field.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Field.kt similarity index 55% rename from app/src/main/java/com/h/pixeldroid/utils/api/objects/Field.kt rename to app/src/main/java/org/pixeldroid/app/utils/api/objects/Field.kt index 8c85c2c1..f7ad2d38 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Field.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Field.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.utils.api.objects +package org.pixeldroid.app.utils.api.objects import java.io.Serializable diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/History.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/History.kt similarity index 56% rename from app/src/main/java/com/h/pixeldroid/utils/api/objects/History.kt rename to app/src/main/java/org/pixeldroid/app/utils/api/objects/History.kt index c3564411..98d9d00a 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/History.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/History.kt @@ -1,8 +1,10 @@ -package com.h.pixeldroid.utils.api.objects +package org.pixeldroid.app.utils.api.objects + +import java.io.Serializable data class History( //Required attributes val day: String, val uses: String, val accounts: String -) +): Serializable diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Instance.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Instance.kt similarity index 59% rename from app/src/main/java/com/h/pixeldroid/utils/api/objects/Instance.kt rename to app/src/main/java/org/pixeldroid/app/utils/api/objects/Instance.kt index bfac27d0..bee5f797 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Instance.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Instance.kt @@ -1,6 +1,7 @@ -package com.h.pixeldroid.utils.api.objects +package org.pixeldroid.app.utils.api.objects -import com.h.pixeldroid.utils.db.entities.InstanceDatabaseEntity.Companion.DEFAULT_MAX_TOOT_CHARS +import org.pixeldroid.app.utils.db.entities.InstanceDatabaseEntity.Companion.DEFAULT_MAX_TOOT_CHARS +import java.io.Serializable data class Instance ( val description: String?, @@ -11,4 +12,4 @@ data class Instance ( val title: String?, val uri: String?, val version: String? -) \ No newline at end of file +): Serializable \ No newline at end of file diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Mention.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Mention.kt similarity index 81% rename from app/src/main/java/com/h/pixeldroid/utils/api/objects/Mention.kt rename to app/src/main/java/org/pixeldroid/app/utils/api/objects/Mention.kt index ce3812b3..b67a6d7b 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Mention.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Mention.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.utils.api.objects +package org.pixeldroid.app.utils.api.objects import java.io.Serializable diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/NodeInfo.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/NodeInfo.kt similarity index 96% rename from app/src/main/java/com/h/pixeldroid/utils/api/objects/NodeInfo.kt rename to app/src/main/java/org/pixeldroid/app/utils/api/objects/NodeInfo.kt index e302c88f..e72b54c1 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/NodeInfo.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/NodeInfo.kt @@ -1,6 +1,6 @@ -package com.h.pixeldroid.utils.api.objects +package org.pixeldroid.app.utils.api.objects -import com.h.pixeldroid.utils.validDomain +import org.pixeldroid.app.utils.validDomain /* See https://nodeinfo.diaspora.software/schema.html and https://pixelfed.social/api/nodeinfo/2.0.json diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Notification.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Notification.kt similarity index 92% rename from app/src/main/java/com/h/pixeldroid/utils/api/objects/Notification.kt rename to app/src/main/java/org/pixeldroid/app/utils/api/objects/Notification.kt index fc5bf9ce..03b3dacc 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Notification.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Notification.kt @@ -1,9 +1,9 @@ -package com.h.pixeldroid.utils.api.objects +package org.pixeldroid.app.utils.api.objects import androidx.room.Entity import androidx.room.ForeignKey import androidx.room.Index -import com.h.pixeldroid.utils.db.entities.UserDatabaseEntity +import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity import java.io.Serializable import java.util.Date diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Poll.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Poll.kt similarity index 55% rename from app/src/main/java/com/h/pixeldroid/utils/api/objects/Poll.kt rename to app/src/main/java/org/pixeldroid/app/utils/api/objects/Poll.kt index 2ccecacb..264b9c21 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Poll.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Poll.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.utils.api.objects +package org.pixeldroid.app.utils.api.objects import java.io.Serializable diff --git a/app/src/main/java/org/pixeldroid/app/utils/api/objects/Relationship.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Relationship.kt new file mode 100644 index 00000000..54821d06 --- /dev/null +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Relationship.kt @@ -0,0 +1,18 @@ +package org.pixeldroid.app.utils.api.objects + +import java.io.Serializable + +data class Relationship( + // Required atributes + val id: String, + val following: Boolean?, + val requested: Boolean?, + val endorsed: Boolean?, + val followed_by: Boolean?, + val muting: Boolean?, + val muting_notifications: Boolean?, + val showing_reblogs: Boolean?, + val blocking: Boolean?, + val domain_blocking: Boolean?, + val blocked_by: Boolean? +) : Serializable diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Report.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Report.kt similarity index 53% rename from app/src/main/java/com/h/pixeldroid/utils/api/objects/Report.kt rename to app/src/main/java/org/pixeldroid/app/utils/api/objects/Report.kt index f8e4630d..ca5b5ced 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Report.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Report.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.utils.api.objects +package org.pixeldroid.app.utils.api.objects import java.io.Serializable diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Results.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Results.kt similarity index 80% rename from app/src/main/java/com/h/pixeldroid/utils/api/objects/Results.kt rename to app/src/main/java/org/pixeldroid/app/utils/api/objects/Results.kt index 30674273..68ef182f 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Results.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Results.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.utils.api.objects +package org.pixeldroid.app.utils.api.objects import java.io.Serializable diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Source.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Source.kt similarity index 55% rename from app/src/main/java/com/h/pixeldroid/utils/api/objects/Source.kt rename to app/src/main/java/org/pixeldroid/app/utils/api/objects/Source.kt index 625532da..8430be4e 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Source.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Source.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.utils.api.objects +package org.pixeldroid.app.utils.api.objects import java.io.Serializable diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Status.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Status.kt similarity index 94% rename from app/src/main/java/com/h/pixeldroid/utils/api/objects/Status.kt rename to app/src/main/java/org/pixeldroid/app/utils/api/objects/Status.kt index 9b88e619..92b2acd7 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Status.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Status.kt @@ -1,21 +1,16 @@ -package com.h.pixeldroid.utils.api.objects +package org.pixeldroid.app.utils.api.objects import android.app.DownloadManager import android.content.Context import android.content.Intent import android.database.Cursor -import android.graphics.ColorMatrix -import android.graphics.ColorMatrixColorFilter import android.net.Uri import android.os.Environment import android.view.View -import android.view.View.GONE -import android.view.View.VISIBLE import androidx.core.net.toUri import com.google.android.material.snackbar.Snackbar -import com.h.pixeldroid.R -import com.h.pixeldroid.databinding.PostFragmentBinding -import com.h.pixeldroid.posts.getDomain +import org.pixeldroid.app.R +import org.pixeldroid.app.posts.getDomain import java.io.File import java.io.Serializable import java.util.* diff --git a/app/src/main/java/org/pixeldroid/app/utils/api/objects/Tag.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Tag.kt new file mode 100644 index 00000000..6b727881 --- /dev/null +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Tag.kt @@ -0,0 +1,29 @@ +package org.pixeldroid.app.utils.api.objects + +import android.content.Context +import android.content.Intent +import androidx.core.content.ContextCompat +import org.pixeldroid.app.posts.feeds.uncachedFeeds.hashtags.HashTagActivity +import java.io.Serializable + +data class Tag( + //Base attributes + val name: String, + val url: String, + //Optional attributes + val history: List? = emptyList()) : Serializable, FeedContent { + //needed to be a FeedContent, this inheritance is a bit fickle. Do not use. + override val id: String + get() = "tag" + + companion object { + const val HASHTAG_TAG = "HashtagTag" + + fun openTag(context: Context, tag: String) { + val intent = Intent(context, HashTagActivity::class.java) + intent.putExtra(HASHTAG_TAG, tag) + ContextCompat.startActivity(context, intent, null) + } + } +} + diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Token.kt b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Token.kt similarity index 77% rename from app/src/main/java/com/h/pixeldroid/utils/api/objects/Token.kt rename to app/src/main/java/org/pixeldroid/app/utils/api/objects/Token.kt index 8681d2fc..04946aef 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/api/objects/Token.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/api/objects/Token.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.utils.api.objects +package org.pixeldroid.app.utils.api.objects data class Token( val access_token: String?, diff --git a/app/src/main/java/com/h/pixeldroid/utils/db/AppDatabase.kt b/app/src/main/java/org/pixeldroid/app/utils/db/AppDatabase.kt similarity index 52% rename from app/src/main/java/com/h/pixeldroid/utils/db/AppDatabase.kt rename to app/src/main/java/org/pixeldroid/app/utils/db/AppDatabase.kt index e81e1d1d..c2a52989 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/db/AppDatabase.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/db/AppDatabase.kt @@ -1,17 +1,17 @@ -package com.h.pixeldroid.utils.db +package org.pixeldroid.app.utils.db import androidx.room.Database import androidx.room.RoomDatabase import androidx.room.TypeConverters -import com.h.pixeldroid.utils.db.dao.* -import com.h.pixeldroid.utils.db.dao.feedContent.NotificationDao -import com.h.pixeldroid.utils.db.dao.feedContent.posts.HomePostDao -import com.h.pixeldroid.utils.db.dao.feedContent.posts.PublicPostDao -import com.h.pixeldroid.utils.db.entities.HomeStatusDatabaseEntity -import com.h.pixeldroid.utils.db.entities.InstanceDatabaseEntity -import com.h.pixeldroid.utils.db.entities.PublicFeedStatusDatabaseEntity -import com.h.pixeldroid.utils.db.entities.UserDatabaseEntity -import com.h.pixeldroid.utils.api.objects.Notification +import org.pixeldroid.app.utils.db.dao.* +import org.pixeldroid.app.utils.db.dao.feedContent.NotificationDao +import org.pixeldroid.app.utils.db.dao.feedContent.posts.HomePostDao +import org.pixeldroid.app.utils.db.dao.feedContent.posts.PublicPostDao +import org.pixeldroid.app.utils.db.entities.HomeStatusDatabaseEntity +import org.pixeldroid.app.utils.db.entities.InstanceDatabaseEntity +import org.pixeldroid.app.utils.db.entities.PublicFeedStatusDatabaseEntity +import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity +import org.pixeldroid.app.utils.api.objects.Notification @Database(entities = [ InstanceDatabaseEntity::class, diff --git a/app/src/main/java/com/h/pixeldroid/utils/db/Converters.kt b/app/src/main/java/org/pixeldroid/app/utils/db/Converters.kt similarity index 97% rename from app/src/main/java/com/h/pixeldroid/utils/db/Converters.kt rename to app/src/main/java/org/pixeldroid/app/utils/db/Converters.kt index acf5aee0..a3f42bfb 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/db/Converters.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/db/Converters.kt @@ -1,9 +1,9 @@ -package com.h.pixeldroid.utils.db +package org.pixeldroid.app.utils.db import androidx.room.TypeConverter import com.google.gson.Gson import com.google.gson.reflect.TypeToken -import com.h.pixeldroid.utils.api.objects.* +import org.pixeldroid.app.utils.api.objects.* import java.util.* class Converters { diff --git a/app/src/main/java/com/h/pixeldroid/utils/db/DBUtils.kt b/app/src/main/java/org/pixeldroid/app/utils/db/DBUtils.kt similarity index 72% rename from app/src/main/java/com/h/pixeldroid/utils/db/DBUtils.kt rename to app/src/main/java/org/pixeldroid/app/utils/db/DBUtils.kt index 08d3a490..0b874a3c 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/db/DBUtils.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/db/DBUtils.kt @@ -1,15 +1,15 @@ -package com.h.pixeldroid.utils.db +package org.pixeldroid.app.utils.db -import com.h.pixeldroid.utils.db.entities.InstanceDatabaseEntity -import com.h.pixeldroid.utils.db.entities.UserDatabaseEntity -import com.h.pixeldroid.utils.api.objects.Account -import com.h.pixeldroid.utils.api.objects.Instance -import com.h.pixeldroid.utils.api.objects.NodeInfo -import com.h.pixeldroid.utils.db.entities.InstanceDatabaseEntity.Companion.DEFAULT_ALBUM_LIMIT -import com.h.pixeldroid.utils.db.entities.InstanceDatabaseEntity.Companion.DEFAULT_MAX_PHOTO_SIZE -import com.h.pixeldroid.utils.db.entities.InstanceDatabaseEntity.Companion.DEFAULT_MAX_TOOT_CHARS -import com.h.pixeldroid.utils.db.entities.InstanceDatabaseEntity.Companion.DEFAULT_MAX_VIDEO_SIZE -import com.h.pixeldroid.utils.normalizeDomain +import org.pixeldroid.app.utils.db.entities.InstanceDatabaseEntity +import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity +import org.pixeldroid.app.utils.api.objects.Account +import org.pixeldroid.app.utils.api.objects.Instance +import org.pixeldroid.app.utils.api.objects.NodeInfo +import org.pixeldroid.app.utils.db.entities.InstanceDatabaseEntity.Companion.DEFAULT_ALBUM_LIMIT +import org.pixeldroid.app.utils.db.entities.InstanceDatabaseEntity.Companion.DEFAULT_MAX_PHOTO_SIZE +import org.pixeldroid.app.utils.db.entities.InstanceDatabaseEntity.Companion.DEFAULT_MAX_TOOT_CHARS +import org.pixeldroid.app.utils.db.entities.InstanceDatabaseEntity.Companion.DEFAULT_MAX_VIDEO_SIZE +import org.pixeldroid.app.utils.normalizeDomain import java.lang.IllegalArgumentException fun addUser(db: AppDatabase, account: Account, instance_uri: String, activeUser: Boolean = true, diff --git a/app/src/main/java/com/h/pixeldroid/utils/db/dao/InstanceDao.kt b/app/src/main/java/org/pixeldroid/app/utils/db/dao/InstanceDao.kt similarity index 84% rename from app/src/main/java/com/h/pixeldroid/utils/db/dao/InstanceDao.kt rename to app/src/main/java/org/pixeldroid/app/utils/db/dao/InstanceDao.kt index c4887174..59ee3771 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/db/dao/InstanceDao.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/db/dao/InstanceDao.kt @@ -1,7 +1,7 @@ -package com.h.pixeldroid.utils.db.dao +package org.pixeldroid.app.utils.db.dao import androidx.room.* -import com.h.pixeldroid.utils.db.entities.InstanceDatabaseEntity +import org.pixeldroid.app.utils.db.entities.InstanceDatabaseEntity @Dao interface InstanceDao { diff --git a/app/src/main/java/com/h/pixeldroid/utils/db/dao/UserDao.kt b/app/src/main/java/org/pixeldroid/app/utils/db/dao/UserDao.kt similarity index 66% rename from app/src/main/java/com/h/pixeldroid/utils/db/dao/UserDao.kt rename to app/src/main/java/org/pixeldroid/app/utils/db/dao/UserDao.kt index d32ba93c..396f152e 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/db/dao/UserDao.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/db/dao/UserDao.kt @@ -1,15 +1,15 @@ -package com.h.pixeldroid.utils.db.dao +package org.pixeldroid.app.utils.db.dao import androidx.room.* -import com.h.pixeldroid.utils.db.entities.UserDatabaseEntity +import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity @Dao interface UserDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun insertUser(user: UserDatabaseEntity) - @Query("UPDATE users SET accessToken = :accessToken WHERE user_id = :id and instance_uri = :instance_uri") - fun updateAccessToken(accessToken: String, id: String, instance_uri: String) + @Query("UPDATE users SET accessToken = :accessToken, refreshToken = :refreshToken WHERE user_id = :id and instance_uri = :instance_uri") + fun updateAccessToken(accessToken: String, refreshToken: String, id: String, instance_uri: String) @Query("SELECT * FROM users") fun getAll(): List diff --git a/app/src/main/java/com/h/pixeldroid/utils/db/dao/feedContent/FeedContentDao.kt b/app/src/main/java/org/pixeldroid/app/utils/db/dao/feedContent/FeedContentDao.kt similarity index 79% rename from app/src/main/java/com/h/pixeldroid/utils/db/dao/feedContent/FeedContentDao.kt rename to app/src/main/java/org/pixeldroid/app/utils/db/dao/feedContent/FeedContentDao.kt index 22673b29..d4985b07 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/db/dao/feedContent/FeedContentDao.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/db/dao/feedContent/FeedContentDao.kt @@ -1,9 +1,9 @@ -package com.h.pixeldroid.utils.db.dao.feedContent +package org.pixeldroid.app.utils.db.dao.feedContent import androidx.paging.PagingSource import androidx.room.Insert import androidx.room.OnConflictStrategy -import com.h.pixeldroid.utils.api.objects.FeedContentDatabase +import org.pixeldroid.app.utils.api.objects.FeedContentDatabase interface FeedContentDao{ diff --git a/app/src/main/java/com/h/pixeldroid/utils/db/dao/feedContent/NotificationDao.kt b/app/src/main/java/org/pixeldroid/app/utils/db/dao/feedContent/NotificationDao.kt similarity index 85% rename from app/src/main/java/com/h/pixeldroid/utils/db/dao/feedContent/NotificationDao.kt rename to app/src/main/java/org/pixeldroid/app/utils/db/dao/feedContent/NotificationDao.kt index b4fa57d2..0a6717df 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/db/dao/feedContent/NotificationDao.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/db/dao/feedContent/NotificationDao.kt @@ -1,9 +1,9 @@ -package com.h.pixeldroid.utils.db.dao.feedContent +package org.pixeldroid.app.utils.db.dao.feedContent import androidx.paging.PagingSource import androidx.room.Dao import androidx.room.Query -import com.h.pixeldroid.utils.api.objects.Notification +import org.pixeldroid.app.utils.api.objects.Notification @Dao interface NotificationDao: FeedContentDao { diff --git a/app/src/main/java/com/h/pixeldroid/utils/db/dao/feedContent/posts/HomePostDao.kt b/app/src/main/java/org/pixeldroid/app/utils/db/dao/feedContent/posts/HomePostDao.kt similarity index 77% rename from app/src/main/java/com/h/pixeldroid/utils/db/dao/feedContent/posts/HomePostDao.kt rename to app/src/main/java/org/pixeldroid/app/utils/db/dao/feedContent/posts/HomePostDao.kt index 3f7b1b4b..2236785a 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/db/dao/feedContent/posts/HomePostDao.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/db/dao/feedContent/posts/HomePostDao.kt @@ -1,10 +1,10 @@ -package com.h.pixeldroid.utils.db.dao.feedContent.posts +package org.pixeldroid.app.utils.db.dao.feedContent.posts import androidx.paging.PagingSource import androidx.room.Dao import androidx.room.Query -import com.h.pixeldroid.utils.db.dao.feedContent.FeedContentDao -import com.h.pixeldroid.utils.db.entities.HomeStatusDatabaseEntity +import org.pixeldroid.app.utils.db.dao.feedContent.FeedContentDao +import org.pixeldroid.app.utils.db.entities.HomeStatusDatabaseEntity @Dao interface HomePostDao: FeedContentDao { diff --git a/app/src/main/java/com/h/pixeldroid/utils/db/dao/feedContent/posts/PublicPostDao.kt b/app/src/main/java/org/pixeldroid/app/utils/db/dao/feedContent/posts/PublicPostDao.kt similarity index 77% rename from app/src/main/java/com/h/pixeldroid/utils/db/dao/feedContent/posts/PublicPostDao.kt rename to app/src/main/java/org/pixeldroid/app/utils/db/dao/feedContent/posts/PublicPostDao.kt index 6658ae40..7901f0a1 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/db/dao/feedContent/posts/PublicPostDao.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/db/dao/feedContent/posts/PublicPostDao.kt @@ -1,10 +1,10 @@ -package com.h.pixeldroid.utils.db.dao.feedContent.posts +package org.pixeldroid.app.utils.db.dao.feedContent.posts import androidx.paging.PagingSource import androidx.room.Dao import androidx.room.Query -import com.h.pixeldroid.utils.db.dao.feedContent.FeedContentDao -import com.h.pixeldroid.utils.db.entities.PublicFeedStatusDatabaseEntity +import org.pixeldroid.app.utils.db.dao.feedContent.FeedContentDao +import org.pixeldroid.app.utils.db.entities.PublicFeedStatusDatabaseEntity @Dao interface PublicPostDao: FeedContentDao { diff --git a/app/src/main/java/com/h/pixeldroid/utils/db/entities/HomeStatusDatabaseEntity.kt b/app/src/main/java/org/pixeldroid/app/utils/db/entities/HomeStatusDatabaseEntity.kt similarity index 97% rename from app/src/main/java/com/h/pixeldroid/utils/db/entities/HomeStatusDatabaseEntity.kt rename to app/src/main/java/org/pixeldroid/app/utils/db/entities/HomeStatusDatabaseEntity.kt index d0a3fcf6..42d0653d 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/db/entities/HomeStatusDatabaseEntity.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/db/entities/HomeStatusDatabaseEntity.kt @@ -1,9 +1,9 @@ -package com.h.pixeldroid.utils.db.entities +package org.pixeldroid.app.utils.db.entities import androidx.room.Entity import androidx.room.ForeignKey import androidx.room.Index -import com.h.pixeldroid.utils.api.objects.* +import org.pixeldroid.app.utils.api.objects.* import java.util.* @Entity( diff --git a/app/src/main/java/com/h/pixeldroid/utils/db/entities/InstanceDatabaseEntity.kt b/app/src/main/java/org/pixeldroid/app/utils/db/entities/InstanceDatabaseEntity.kt similarity index 91% rename from app/src/main/java/com/h/pixeldroid/utils/db/entities/InstanceDatabaseEntity.kt rename to app/src/main/java/org/pixeldroid/app/utils/db/entities/InstanceDatabaseEntity.kt index 2906dcb1..58e71342 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/db/entities/InstanceDatabaseEntity.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/db/entities/InstanceDatabaseEntity.kt @@ -1,8 +1,7 @@ -package com.h.pixeldroid.utils.db.entities +package org.pixeldroid.app.utils.db.entities import androidx.room.Entity import androidx.room.PrimaryKey -import com.h.pixeldroid.utils.api.objects.Instance @Entity(tableName = "instances") data class InstanceDatabaseEntity ( diff --git a/app/src/main/java/com/h/pixeldroid/utils/db/entities/PublicFeedStatusDatabaseEntity.kt b/app/src/main/java/org/pixeldroid/app/utils/db/entities/PublicFeedStatusDatabaseEntity.kt similarity index 97% rename from app/src/main/java/com/h/pixeldroid/utils/db/entities/PublicFeedStatusDatabaseEntity.kt rename to app/src/main/java/org/pixeldroid/app/utils/db/entities/PublicFeedStatusDatabaseEntity.kt index f08b6eba..9986d601 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/db/entities/PublicFeedStatusDatabaseEntity.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/db/entities/PublicFeedStatusDatabaseEntity.kt @@ -1,9 +1,9 @@ -package com.h.pixeldroid.utils.db.entities +package org.pixeldroid.app.utils.db.entities import androidx.room.Entity import androidx.room.ForeignKey import androidx.room.Index -import com.h.pixeldroid.utils.api.objects.* +import org.pixeldroid.app.utils.api.objects.* import java.util.* @Entity( diff --git a/app/src/main/java/com/h/pixeldroid/utils/db/entities/UserDatabaseEntity.kt b/app/src/main/java/org/pixeldroid/app/utils/db/entities/UserDatabaseEntity.kt similarity index 94% rename from app/src/main/java/com/h/pixeldroid/utils/db/entities/UserDatabaseEntity.kt rename to app/src/main/java/org/pixeldroid/app/utils/db/entities/UserDatabaseEntity.kt index cd0e8b20..54725b4d 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/db/entities/UserDatabaseEntity.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/db/entities/UserDatabaseEntity.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.utils.db.entities +package org.pixeldroid.app.utils.db.entities import androidx.room.Entity import androidx.room.ForeignKey diff --git a/app/src/main/java/com/h/pixeldroid/utils/di/APIModule.kt b/app/src/main/java/org/pixeldroid/app/utils/di/APIModule.kt similarity index 59% rename from app/src/main/java/com/h/pixeldroid/utils/di/APIModule.kt rename to app/src/main/java/org/pixeldroid/app/utils/di/APIModule.kt index 2d6cb27f..06ff09a8 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/di/APIModule.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/di/APIModule.kt @@ -1,8 +1,9 @@ -package com.h.pixeldroid.utils.di +package org.pixeldroid.app.utils.di -import com.h.pixeldroid.utils.api.PixelfedAPI -import com.h.pixeldroid.utils.db.AppDatabase -import com.h.pixeldroid.utils.db.entities.UserDatabaseEntity +import org.pixeldroid.app.utils.api.PixelfedAPI +import org.pixeldroid.app.utils.api.objects.Token +import org.pixeldroid.app.utils.db.AppDatabase +import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity import dagger.Module import dagger.Provides import kotlinx.coroutines.runBlocking @@ -22,17 +23,30 @@ class APIModule{ } } -class TokenAuthenticator(val user: UserDatabaseEntity, val db: AppDatabase) : Authenticator { +class TokenAuthenticator(val user: UserDatabaseEntity, val db: AppDatabase, val apiHolder: PixelfedAPIHolder) : Authenticator { private val pixelfedAPI = PixelfedAPI.createFromUrl(user.instance_uri) + // Returns the number of tries for this response by walking through the priorResponses + private fun Response.responseCount(): Int { + var result = 1 + var response: Response? = priorResponse + + while (response != null) { + result++ + response = response.priorResponse + } + return result + } + + override fun authenticate(route: Route?, response: Response): Request? { - if (response.request.header("Authorization") != null) { - return null // Give up, we've already failed to authenticate. + if (response.responseCount() > 3) { + return null // Give up, we've already failed to authenticate a couple times } // Refresh the access_token using a synchronous api request - val newAccessToken: String? = try { + val newAccessToken: Token = try { runBlocking { pixelfedAPI.obtainToken( scope = "", @@ -40,43 +54,50 @@ class TokenAuthenticator(val user: UserDatabaseEntity, val db: AppDatabase) : Au refresh_token = user.refreshToken, client_id = user.clientId, client_secret = user.clientSecret - ).access_token + ) } }catch (e: Exception){ - null + return null } - if (newAccessToken != null) { - db.userDao().updateAccessToken(newAccessToken, user.user_id, user.instance_uri) + // Save the new access token and refresh token + if (newAccessToken.access_token != null && newAccessToken.refresh_token != null) { + db.userDao().updateAccessToken( + newAccessToken.access_token, + newAccessToken.refresh_token, + user.user_id, user.instance_uri + ) + apiHolder.setToCurrentUser() } // Add new header to rejected request and retry it return response.request.newBuilder() - .header("Authorization", "Bearer ${newAccessToken.orEmpty()}") + .header("Authorization", "Bearer ${newAccessToken.access_token.orEmpty()}") .build() } } -class PixelfedAPIHolder(db: AppDatabase?){ +class PixelfedAPIHolder(private val db: AppDatabase){ private val intermediate: Retrofit.Builder = Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + var api: PixelfedAPI? = - db?.userDao()?.getActiveUser()?.let { - setDomainToCurrentUser(db, it) + db.userDao().getActiveUser()?.let { + setToCurrentUser(it) } - fun setDomainToCurrentUser( - db: AppDatabase, + fun setToCurrentUser( user: UserDatabaseEntity = db.userDao().getActiveUser()!! ): PixelfedAPI { val newAPI = intermediate .baseUrl(user.instance_uri) .client( - OkHttpClient().newBuilder().authenticator(TokenAuthenticator(user, db)) + OkHttpClient().newBuilder().authenticator(TokenAuthenticator(user, db, this)) .addInterceptor { it.request().newBuilder().run { header("Accept", "application/json") + header("Authorization", "Bearer ${user.accessToken}") it.proceed(build()) } }.build() diff --git a/app/src/main/java/com/h/pixeldroid/utils/di/ApplicationComponent.kt b/app/src/main/java/org/pixeldroid/app/utils/di/ApplicationComponent.kt similarity index 67% rename from app/src/main/java/com/h/pixeldroid/utils/di/ApplicationComponent.kt rename to app/src/main/java/org/pixeldroid/app/utils/di/ApplicationComponent.kt index 253cd6e1..3fdff9b7 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/di/ApplicationComponent.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/di/ApplicationComponent.kt @@ -1,11 +1,11 @@ -package com.h.pixeldroid.utils.di +package org.pixeldroid.app.utils.di import android.app.Application import android.content.Context -import com.h.pixeldroid.utils.BaseActivity -import com.h.pixeldroid.utils.PixelDroidApplication -import com.h.pixeldroid.utils.db.AppDatabase -import com.h.pixeldroid.utils.BaseFragment +import org.pixeldroid.app.utils.BaseActivity +import org.pixeldroid.app.utils.PixelDroidApplication +import org.pixeldroid.app.utils.db.AppDatabase +import org.pixeldroid.app.utils.BaseFragment import dagger.Component import javax.inject.Singleton diff --git a/app/src/main/java/com/h/pixeldroid/utils/di/ApplicationModule.kt b/app/src/main/java/org/pixeldroid/app/utils/di/ApplicationModule.kt similarity index 92% rename from app/src/main/java/com/h/pixeldroid/utils/di/ApplicationModule.kt rename to app/src/main/java/org/pixeldroid/app/utils/di/ApplicationModule.kt index 16bca60b..88b8008e 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/di/ApplicationModule.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/di/ApplicationModule.kt @@ -1,4 +1,4 @@ -package com.h.pixeldroid.utils.di +package org.pixeldroid.app.utils.di import android.app.Application import android.content.Context diff --git a/app/src/main/java/com/h/pixeldroid/utils/di/DatabaseModule.kt b/app/src/main/java/org/pixeldroid/app/utils/di/DatabaseModule.kt similarity index 62% rename from app/src/main/java/com/h/pixeldroid/utils/di/DatabaseModule.kt rename to app/src/main/java/org/pixeldroid/app/utils/di/DatabaseModule.kt index d9fda875..6b2e4dbe 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/di/DatabaseModule.kt +++ b/app/src/main/java/org/pixeldroid/app/utils/di/DatabaseModule.kt @@ -1,8 +1,8 @@ -package com.h.pixeldroid.utils.di +package org.pixeldroid.app.utils.di import android.content.Context import androidx.room.Room -import com.h.pixeldroid.utils.db.AppDatabase +import org.pixeldroid.app.utils.db.AppDatabase import dagger.Module import dagger.Provides import javax.inject.Singleton @@ -16,9 +16,6 @@ class DatabaseModule(private val context: Context) { return Room.databaseBuilder( context, AppDatabase::class.java, "pixeldroid" - ).allowMainThreadQueries() - //TODO remove this for 1.0 release - .fallbackToDestructiveMigration() - .build() + ).allowMainThreadQueries().build() } } \ No newline at end of file diff --git a/app/src/main/res/drawable/cloud_done_24.xml b/app/src/main/res/drawable/cloud_done_24.xml new file mode 100644 index 00000000..4ba3a6ea --- /dev/null +++ b/app/src/main/res/drawable/cloud_done_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/cloud_off_24.xml b/app/src/main/res/drawable/cloud_off_24.xml new file mode 100644 index 00000000..7688eca1 --- /dev/null +++ b/app/src/main/res/drawable/cloud_off_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/heart_anim.xml b/app/src/main/res/drawable/heart_anim.xml new file mode 100644 index 00000000..0ca38bea --- /dev/null +++ b/app/src/main/res/drawable/heart_anim.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_followers.xml b/app/src/main/res/layout/activity_followers.xml index ada0701d..e93039d1 100644 --- a/app/src/main/res/layout/activity_followers.xml +++ b/app/src/main/res/layout/activity_followers.xml @@ -1,9 +1,5 @@ - - \ No newline at end of file + android:layout_height="match_parent"/> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index a7fed3d6..082aad05 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -6,7 +6,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" - tools:context="com.h.pixeldroid.MainActivity"> + tools:context="org.pixeldroid.app.MainActivity"> - - + app:layout_constraintTop_toTopOf="parent" + app:drawableStartCompat="@drawable/cloud_off_24" + app:drawableTint="@color/colorPrimaryError" /> - - - + tools:visibility="visible" /> - - + diff --git a/app/src/main/res/layout/fragment_search.xml b/app/src/main/res/layout/fragment_search.xml index 8b8d3cdd..e703640f 100644 --- a/app/src/main/res/layout/fragment_search.xml +++ b/app/src/main/res/layout/fragment_search.xml @@ -39,7 +39,9 @@ - + - + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/image_album_creation.xml b/app/src/main/res/layout/image_album_creation.xml index f63f66fb..1409a55e 100644 --- a/app/src/main/res/layout/image_album_creation.xml +++ b/app/src/main/res/layout/image_album_creation.xml @@ -1,7 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/image_carousel.xml b/app/src/main/res/layout/image_carousel.xml index 52500e18..3bbd86fe 100644 --- a/app/src/main/res/layout/image_carousel.xml +++ b/app/src/main/res/layout/image_carousel.xml @@ -42,13 +42,14 @@ android:id="@+id/editMediaDescriptionLayout" android:layout_width="match_parent" android:layout_height="wrap_content" - android:visibility="gone" android:background="#4D000000" + android:visibility="gone" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toTopOf="@+id/indicator" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_goneMarginBottom="8dp"> + app:layout_goneMarginBottom="8dp" + tools:visibility="visible"> @@ -153,7 +154,7 @@ android:background="?attr/selectableItemBackgroundBorderless" android:contentDescription="@string/switch_to_carousel" android:src="@drawable/view_carousel_black_24dp" - android:tint="@color/white" + app:tint="@color/white" android:visibility="gone" app:layout_constraintBottom_toBottomOf="@+id/indicator" app:layout_constraintEnd_toEndOf="parent" diff --git a/app/src/main/res/layout/post_fragment.xml b/app/src/main/res/layout/post_fragment.xml index 6d538ec2..2bb55c1a 100644 --- a/app/src/main/res/layout/post_fragment.xml +++ b/app/src/main/res/layout/post_fragment.xml @@ -55,7 +55,7 @@ android:layout_marginTop="10dp" app:layout_constraintTop_toBottomOf="@+id/profilePic"> - - + + + Kamera wechseln Konnte die App nicht mit diesem Server verbinden Konnte die Informationen der Instanz nicht abrufen - Fehler beim Hochladen der Bilder! + Fehler beim Hochladen! Standard (Systemeinstellung) Berechtigung verweigert Bild kann nicht gespeichert werden @@ -48,7 +48,7 @@ Upload-Fehler: falsches Bildformat. Hochladen des Beitrags fehlgeschlagen Konto hinzufügen - Ein weiteres Pixelfed-Konto hinzufügen + Weiteres Pixelfed-Konto hinzufügen Hell Dunkel Kommentieren @@ -79,10 +79,10 @@ KONTEN BEITRÄGE Hochzuladendes Bild - {gmd_cloud_off} Hochladen der Medien fehlgeschlagen, versuche es nochmal oder überprüfe deine Netzwerkverbindung - {gmd_cloud_done} Hochladen der Medien abgeschlossen + Hochladen fehlgeschlagen, versuche es noch einmal oder überprüfe deine Verbindung + Hochladen abgeschlossen Fehler beim Hochladen: Falsches Request Format - Konnte den Feed nicht laden + Feed konnte nicht geladen werden Erstellt am %1$s Für das Herunterladen von Bildern müssen Sie eine Schreibgenehmigung erteilen! Für die Teilen von Bildern müssen Sie eine Schreibgenehmigung erteilen! @@ -127,7 +127,7 @@ Öffne Menü Profilbild Bearbeiten - Meldung konnte nicht gesendet werden + Konnte nicht gemeldet werden Gemeldet {gmd_check_circle} Melde @%1$ss Beitrag Dieser Beitrag ist ein Album @@ -139,12 +139,14 @@ Eines der Bilder im Beitrag Benutzerdaten konnten nicht geladen werden - %d Beitrag - %d Beiträge + %d +\nBeitrag + %d +\nBeiträge %d Kommentar - %d Kommentar + %d Kommentare Ergänze hier eine Medienbeschreibung hier… Bildbeschreibung speichern @@ -161,4 +163,35 @@ \nWenn du keine kennst kannst u hier nachsehen: https://pixelfed.org/join \n \nMehr Informationen zu Pixelfed findest du hier: https://pixelfed.org + Löschen fehlgeschlagen, Fehlermeldung %1$d + Followeranfrage zurückziehen\? + Hier gibt es nichts zu sehen :( + + %d +\nFolgt + %d +\nFolgt + + + %d +\nFollower + %d +\nFollower + + + Einmal geteilt + %d mal geteilt + + + %d Like + %d Likes + + Serverfehler %1$d. + Die Größe von Bild %1$d im Album übersteigt mit %2$d kB die von deiner Instanz festgelegte Obergrenze von zulässige Obergrenze von %3$d kB je Bild. + Du hast mehr Bilder ausgewählt, als auf deinem Server zulässig sind (%1$s). Bilder jenseits des Limits wurden nicht berücksichtigt. + Die API ist auf deiner Instanz nicht aktiv. Bitte kontaktiere den Betreiber deiner Instanz, damit sie aktiviert werden kann. + Followeranfrage + Beitrag konnte nicht gelöscht werden. Internetverbindung unterbrochen\? + Bearbeitung nicht verfügbar. + \"Entdecke\" lädt nicht endlos. Nach unten ziehen, um weitere Bilder zu laden. \ No newline at end of file diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index e7659eaf..3447bddd 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -92,4 +92,104 @@ Bien, espera. Procesando imagen, ¡Espera a que termine! ¡Nada que ver aquí! + + %d +\nSiguiendo + %d +\nSiguiendo + + + La descripción debe contener por lo menos %d caracter. + La descripción debe contener por lo menos %d caracteres. + + No se pudo borrar la publicación, quizás sea tu conexión\? + No se pudo borrar la publicación, error %1$d + Imagen mostrando un panda rojo, la mascota de Pixelfed, usando un móvil + Reporta problemas o contribuye a la aplicación: + Ayuda a traducir PixelDroid a tu lenguaje: + Lenguaje + ¿Borrar esta publicación\? + Borrar + Este panda está triste. Desliza hacia abajo para intentarlo de nuevo. + Algo fue mal… + \'Descubre\' no carga infinitamente. Desliza hacia abajo para cargar más imágenes. + DESCUBRE + Abrir el menú lateral + Imagen de perfil + Editar + No se pudo enviar el reporte + Reportado {gmd_check_circle} + Reportar la publicación de @%1$s + Mensaje opcional para moderadores/administradores + Compartir enlace + Reportar + Más opciones + La búsqueda no puede estar vacía + seguidos por %1$s + Seguidores de %1$s + Publicación de %1$s + Sobre + PixelDroid es software libre y código abierto, licenciado bajo la GNU General Public License (versión 3 o posterior) + Web del proyecto: https://pixeldroid.org + Dependencias y licencias + Sobre PixelDroid + ¿Cancelar la petición de seguimiento\? + Seguimiento pedido + Dejar de seguir + Nada que ver aquí :( + Falló al abrir la página de edición + + %d +\nSeguidor + %d +\nSeguidores + + + %d +\nPublicación + %d +\nPublicaciones + + Esta publicación es un album + Enviar comentario + Añadir un comentario + + %d comentario + %d comentarios + + + %d Compartido + %d Compartidos + + + %d Me gusta + %d Me gustas + + No, cancelar edición + ¿Guardar tus ediciones\? + Botón para recortar o rotar la imagen + Previsualización de la imagen siendo editada + Previsualización del filtro + Código de error devuelto por el servidor: %1$d + El tamaño de la imagen número %1$d del álbum, supera el máximo permitido por esta instancia (%2$d kB, siendo el límite: %3$d kB). Podrías no subirla. + Has escogido más imágenes que el máximo que tu servidor permite (%1$s). Las imágenes por encima de ese límite serán ignoradas. + Añadir una descripción del medio aquí… + Guardar descripción de la imagen + Cambiar a carrusel + Cambiar a visión cuadrícula + Una de las imágenes de la publicación + Añadir una foto + La API no está activada en esta instancia. Contacta con tu administrador para pedirle que lo active. + Quizás estés confundido/a por el campo de texto pidiendo el dominio de tu \'instancia\'. +\n +\nPixelfed es una plataforma descentralizada y forma parte del \'fediverso\', lo que significa que ambas plataformas tienen algo en común que las permite interconectarse, como por ejemplo con Mastodon (ver https://joinmastodon.org). +\n +\nEsto quiere decir que debes elegir que servidor o \'instancia\' de Pixelfed utilizar. Si no conoces ninguna de antemano, te recomendamos descubrir una aquí: https://pixelfed.org/join +\n +\nPara más información sobre Pixelfed, puedes ir a: https://pixelfed.org + La votación de %1$s ha terminado + Cancelar iniciar sesión + Vale, continuar de todas formas + Eso no parece ser una instancia de Pixelfed, por lo que la App podría no funcionar adecuadamente. + No se pudo obtener la información del usuario \ No newline at end of file diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index ca162235..7da38f74 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -65,7 +65,7 @@ Argitalpena igotzean errorea Iruzkina: %1$s argitaratua! Argitalpena ongi kargatu da - {gmd_cloud_off} Multimedia-kargak huts egin du, saiatu berriro edo egiaztatu sareko egoera + Multimedia-igoerak huts egin du, saiatu berriro edo egiaztatu sareko egoera Karga errorea: eskaera formatu txarra Karga errorea: irudi-formatu okerra. ARGITALPENAK @@ -86,7 +86,7 @@ %1$s(e)n argitaratua TRAOLAK KONTUAK - {gmd_cloud_done} Multimedia karga amaitu da + Multimedia igoera amaitu da Argitalpena igotzeak huts egin du Ez, utzi editatzeari Zure edizioak gorde\? @@ -121,16 +121,22 @@ Hemen ez dago ezer! Utzi jarraitzeari - %d jarraitzen - %d jarraitzen + %d +\njarraitzen + %d +\njarraitzen - Jarraitzaile %d - %d jarraitzaile + Jarraitzaile +\n%d + %d +\njarraitzaile - Argitalpen %d - %d argitalpen + Argitalpen +\n%d + %d +\nargitalpen Argitalpen hau album bat da Bidali iruzkina @@ -181,4 +187,11 @@ Albumean %1$d zenbakia duen irudiaren tamainak instantziak onartutako gehienezko tamaina gainditzen du (%2$d kB ditu, eta muga %3$d kB da). Baliteke ezin igo ahal izatea. Zerbitzariak onartutako kopurua (%1$s) baino irudi gehiago aukeratu dituzu. Mugatik gorako irudiei ez ikusia egin zaie. APIa ez dago aktibo instantzia honetan. Jarri zure administratzailearekin kontaktuan aktibatzeko. + Aurkikuntza ez da infinituki kargatzen. Tira irudi gehiago kargatzeko. + #%1$s + %1$s fitxategia ez da aurkitu + Huts egin du edizio orria irekitzean + Ez dago ezer hemen :( + Jarraitzeko eskaera + Jarraitzeko eskaera ezeztatu\? \ No newline at end of file diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 32000650..ff08b9a3 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -13,8 +13,8 @@ زمینه ‏%1$s شما را دنبال کرد ‏%1$s به شما اشاره کرد - ‏%1$s مطلب شما را هم‌رسانی کرد - ‏%1$s مطلب شما را پسندید + ‏%1$s فرستهٔ شما را هم‌رسانی کرد + ‏%1$s فرستهٔ شما را پسندید توضیحات… بفرست نمونه چیست؟ @@ -32,7 +32,7 @@ تغییر دوربین نگارخانه هم‌رسانی تصویر… - نظری روی این مطلب نیست… + نظری روی این فرسته نیست… دامنهٔ نمونهٔ شما اتصال به پیکسل‌فد پیکسل‌دروید @@ -51,8 +51,8 @@ خطا در بارگذاری تصویر! خطای بارگذاری: تصویر با قالب نادرست. خطای بارگذاری: درخواست با قالب نادرست - بارگذاری مطلب ناموفق بود - مطلب با موفقیت بارگذاری شد + بارگذاری فرسته ناموفق بود + فرسته با موفقیت بارگذاری شد عادی مشکلی حین بارکردن رخ داد نتوانستیم خوراک را دریافت کنیم @@ -74,7 +74,7 @@ نتوانستیم پی‌گیری را لغو کنیم توکن دسترسی نامعتبر است - -\nمطلب +\nفرسته‌ها - \nپی‌گیرنده فاقد نام کاربری @@ -82,12 +82,12 @@ ویرایش نمایه جستجو مطالب - ‏{gmd_cloud_done} بارگذاری رسانه کامل شد + بارگذاری رسانه به پایان رسید تصویری که در حال فرستاده شدن است تلاش دوباره - \nپی‌گیری - ‏{gmd_cloud_off} بارگذاری رسانه شکست خورد، وضعیت شبکه را بررسی کرده و دوباره تلاش کنید + بارگذاری رسانه شکست خورد، وضعیت شبکه را بررسی کرده یا دوباره تلاش کنید تصویر برش یافته از دسترس خارج شده است خوب، منتظر می‌مانم. منتظر بمانید تا پردازش تصویر پایان یابد! @@ -102,7 +102,7 @@ درباره پیکسل‌دروید پی‌گیری‌های %1$s پی‌گیرندگان %1$s - مطلب %1$s + فرستهٔ %1$s لغو پیگیری کشف گشودن فهرست کشویی @@ -135,8 +135,10 @@ ناتوانی در دریافت اطلاعات کاربر تصویر، یک پاندای قرمز که شگونهٔ پیکسل‌فد است را گوشی به دست نشان می‌دهد - %d فرسته - %d فرسته + %d +\nفرسته + %d +\nفرسته %d نظر @@ -154,12 +156,16 @@ خیر، ویرایش لغو شود ویرایش‌ها ذخیره شوند؟ - %d پی‌گیر - %d پی‌گیر + %d +\nپی‌گیر + %d +\nپی‌گیر - %d پی‌گرفته - %d پی‌گرفته + %d +\nپی‌گرفته + %d +\nپی‌گرفته این جا توضیحات رسانه را وارد کنید… ذخیره توضیحات تصویر @@ -181,4 +187,11 @@ روی این نمونه، API فعال نیست. با مدیر نمونه تماس گرفته و از او بخواهید آن را فعال کند. نتوانستیم فرسته را پاک کنیم. به اینترنت وصل هستید؟ نتوانستیم این فرسته را پاک کنیم. خطا: %1$d + درخواست پیگیری لغو شود؟ + درخواست پیگیری فرستاده شد + اینجا چیزی برای دیدن نیست :( + ناتوانی در باز کردن صفحه ویرایش + بخش کشف به صورت بی‌انتها بار نمی‌شود. برای تازه‌سازی و دریافت تصاویر دیگر، صفحه را به پایین بکشید. + پروندهٔ %1$s یافت نشد + #%1$s \ No newline at end of file diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml new file mode 100644 index 00000000..d4e1f3ff --- /dev/null +++ b/app/src/main/res/values-fi/strings.xml @@ -0,0 +1,133 @@ + + + Tämä ei näytä olevan Pixelfed-instanssi, joten sovellus voi rikkoutua odottamattomasti. + Lisää median kuvaus tähän… + Tallenna kuvan kuvaus + Vaihda karuselliin + Julkaisun latausvirhe + Julkaisun lataus onnistui + Julkaisun lataaminen epäonnistui + Latausvirhe: väärä kuvamuoto. + Virhe kuvan lataamisessa! + + Kuvaus saa sisältää enintään %d merkkiä. + Kuvaus saa sisältää enintään %d merkkiä. + + Kuvan tallentaminen epäonnistui + Lupa evätty + API ei ole käytössä tässä instansissa. Pyydä ylläpitäjää ottamaan se käyttöön. + Sinun on oltava verkossa, jotta voit lisätä ensimmäisen tilin ja käyttää PixelDroidia :( + Saatat olla hämmentynyt tekstikentästä, jossa kysytään \'instanssisi\' verkkotunnusta. +\n +\nPixelfed on hajautettu alusta ja osa \'fediverseä\', mikä tarkoittaa että se voi puhua muiden alustojen kanssa, jotka puhuvat samaa kieltä, kuten Mastodon (katso https://joinmastodon.org). +\n +\nSe tarkoittaa myös, että sinun on valittava käytettävä palvelin eli \'instanssi\' käyttääksesi Pixelfediä. Jos et tiedä yhtään instanssia, voit katsoa täältä: https://pixelfed.org/join +\n +\nLisätietoja Pixelfedistä saat täältä: https://pixelfed.org + Selainta ei voitu käynnistää, onko sinulla sitä\? + PixelDroid on vapaa ja avoimen lähdekoodin ohjelma, jonka lisenssi on GNU General Public License (versio 3 tai uudempi) + Auta kääntämään PixelDroid omalle kielellesi: + Ei kommentteja tässä julkaisussa… + Peruuta seuraamispyyntö\? + Vaihda ruudukkonäkymään + Lisää toinen Pixelfed-tili + Instanssisi verkkotunnus + %1$s tykkäsi julkaisustasi + %1$s jakoi julkaisusi + Poistetaanko tämä julkaisu\? + Projektin verkkosivu: https://pixeldroid.org + Lisää kommentti + Tallenna galleriaan… + Ei, peruuta muokkaukset + Tallennetaanko muokkaukset\? + Lisää kuva + %1$s mainitsi sinut + Peruuta kirjautuminen + OK, jatka jokatapauksessa + Ei käyttäjänimeä + Yritä uudelleen + TILIT + Kuva tallennettu + Yhdistä Pixelfediin + Mikä on instanssi\? + %1$s seurasi sinua + Seuraa laitteen teemaa + Profiilikuva + Jaa linkki + %1$s julkaisi + Tietoja PixelDroid + Muokkaa profiilia + Seurauspyyntö + - +\nSeurataan + - +\nSeuraajat + - +\nJulkaisut + + %d +\nSeurataan + %d +\nSeurataan + + + %d +\nSeuraaja + %d +\nSeuraajaa + + + %d +\nJulkaisu + %d +\nJulkaisua + + + %d kommentti + %d kommenttia + + Jaa Kuva + + %d Jako + %d Jakoa + + + %d Tykkäys + %d Tykkäystä + + Ei kuvausta + Jaa kuva… + Lisää tili + Kirjaudu ulos + Sovelluksen teema + Virheellinen verkkotunnus + Kieli + Poista + Muokkaa + Ilmianna + #%1$s + Tietoja + MERKINNÄT + JULKAISUT + Hae + Seurataan + Seuraa + Kommentti + Ladataan… + Galleria + Normaali + Muokkaa + SUODATIN + VÄRIKYLLÄISYYS + KONTRASTI + KIRKKAUS + julkaise + Kuvaus… + Tumma + Vaalea + Teema + Asetukset + Asetukset + Profiili + PixelDroid + diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 409203ed..31bcfe19 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -84,10 +84,10 @@ PUBLICATIONS COMPTES HASHTAGS - {gmd_cloud_done} Média téléversé avec succès + Média téléversé avec succès Réessayez Image en cours de publication - {gmd_cloud_off} Échec du téléversement du média, réessayez ou vérifiez l\'état du réseau + Échec du téléversement du média, réessayez ou vérifiez l\'état du réseau Impossible de récupérer l\'image après le recadrage D\'accord, attendez pour ça. Toujours en train de traiter l\'image, attendez tout d\'abord que cela se termine ! @@ -152,16 +152,22 @@ \n \nPour plus d\'informations sur Pixelfed, vous pouvez consulter le site suivant : https://pixelfed.org - %d Abonnement - %d Abonnements + %d +\nAbonnement + %d +\nAbonnements - %d Abonné·e - %d Abonné·e·s + %d +\nAbonné·e + %d +\nAbonné·e·s - %d Publication - %d Publications + %d +\nPublication + %d +\nPublications %d commentaire @@ -179,4 +185,6 @@ La description doit contenir au moins %d lettre. La description doit contenir au moins %d lettres. + Impossible de supprimer la publication, erreur %1$d + Rien à voir par ici :( \ No newline at end of file diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 403d6883..a44fe2fb 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -84,9 +84,9 @@ Escuro Claro Por omisión (do sistema) - {gmd_cloud_off} Fallou a subida do ficheiro, inténtao outra vez e comproba a conexión + Fallou a subida do ficheiro, inténtao outra vez ou comproba a conexión Imaxe que se publicou - {gmd_cloud_done} Subida do ficheiro completada + Subida do multimedia completada Reintentar Nada por aquí! Tras o recorte non se puido obter a imaxe @@ -128,16 +128,22 @@ Non se obtivo a información da usuaria Imaxe amosando un panda vermello, mascota de Pixelfed, usando un móbil - %d seguimento - %d seguimentos + %d +\nseguimento + %d +\nseguimentos - %d Seguidora - %d Seguidoras + %d +\nSeguidora + %d +\nSeguidoras - %d Publicación - %d Publicacións + %d +\nPublicación + %d +\nPublicacións Esta publicación é un álbume Enviar comentario @@ -181,4 +187,10 @@ \nPara saber máis acerca de Pixelfed, podes mirar aquí: https://pixelfed.org Non se puido eliminar a publicación, tes conexión a internet\? Non se puido eliminar a publicación, erro %1$d + Cancelar a solicitude de seguimento\? + Seguimento solicitado + Nada por aquí :( + Non se puido abrir a páxina de edición + Descubrimento non carga indefinidamente. Arrastra hacia abaixo para ter máis imaxes. + Non se atopou o ficheiro %1$s \ No newline at end of file diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml new file mode 100644 index 00000000..c263d16b --- /dev/null +++ b/app/src/main/res/values-id/strings.xml @@ -0,0 +1,160 @@ + + + Pengaturan + Domain tidak valid + Tidak dapat mendaftarkan aplikasi ini dengan server ini + Gagal mendapatkan token + Tidak dapat mendapatkan informasi instansi + Pengaturan + Tema Aplikasi + Tema + Batal masuk + Terang + Gelap + %1$s mengikuti Anda + %1$s membagikan postingan Anda + %1$s menyukai postingan Anda + Apa itu instansi\? + Keluar + Tambahkan Akun Pixelfed lain + Izin ditolak + Gambar berhasil disimpan + Kesalahan pengunggahan: format gambar salah. + Kesalahan pengunggahan: format permintaan buruk + Postingan berhasil diunggah + postingan + Simpan keterangan gambar + Kode kesalahan yang dikembalikan oleh server: %1$d + KECERAHAN + KONTRAS + KEJENUHAN + FILTER-FILTER + Sunting + Normal + Masih memproses gambar, tunggu sampai itu selesai dahulu! + Oke, tunggu itu. + Tidak dapat menerima gambar setelah pemotongan + Simpan suntingan-suntingan Anda\? + Tidak, batalkan suntingan + Tangkap + Ubah kamera + Galeri + Suatu kesalahan terjadi saat memuat + Bagikan gambar… + Simpan ke Galeri… + Mengunduh… + Gambar berhasil diunduh + Diposting pada %1$s + Tidak ada komentar di postingan ini… + Komentar tidak boleh kosong! + Bagikan Gambar + Komentar: %1$s diposting! + Komentar + + %d komentar + + Tambahkan sebuah komentar + Kirim komentar + Postingan ini adalah sebuah album + + %d +\nPostingan + + + %d +\nPengikut + + + %d +\nDiikuti + + Tidak ada yang bisa dilihat di sini :( + Tidak dapat menampilkan tombol ikuti + Gagal membuka halaman penyuntingan + + %d Suka + + + %d Pembagian + + Tindakan ini tidak diperbolehkan + Tidak dapat berhenti mengikuti + Token akses ini tidak valid + - +\nPostingan + - +\nDiikuti + Tidak Ada Nama Pengguna + Ikuti + Berhenti Mengikuti + Sunting profil + Cari + POSTINGAN-POSTINGAN + TAGAR-TAGAR + Pengunggahan media selesai + Gambar yang sedang diposting + Coba lagi + Tidak ada yang dapat dilihat di sini! + Tentang PixelDroid + Tentang + Postingan %1$s + Pengikut-pengikut %1$s + %1$s mengikuti + Kata pencarian tidak dapat kosong + Lebih banyak pilihan + Laporkan + Bagikan Tautan + Pesan opsional untuk para mod/admin + Laporkan postingan @%1$s + Tidak dapat mengirim laporan + Sunting + Gambar profil + TEMUKAN + Temukan tidak memuat selamanya. Tarik untuk memuat ulang gambar lain. + Suatu kesalahan terjadi… + Hapus + Hapus postingan ini\? + Bahasa + Bantu terjemahkan PixelDroid ke bahasa Anda: + Laporkan masalah atau berkontribusi ke aplikasi ini: + Gambar yang menunjukkan seekor panda merah, maskot dari Pixelfed, menggunakan sebuah ponsel + Tidak dapat menghapus postingan, kesalahan %1$d + Tidak dapat menghapus postingan, periksa koneksi Anda\? + PixelDroid + Profil Saya + Tidak dapat meluncurkan sebuah browser, apakah Anda memilikinya\? + Tidak dapat mengautentikasi + Tidak dapat mendapatkan informasi pengguna + Oke, tetap lanjutkan + Default (Mengikuti sistem) + Ini kelihatannya bukan sebuah instansi Pixelfed, sehingga aplikasi ini dapat rusak dengan cara yang tak terduga. + Domain dari instansi Anda + API tidak diaktivasi di instansi ini. Hubungi administrator Anda untuk meminta mereka mengaktivasikan API. + Tambahkan Akun + Tidak dapat menyimpan gambar + + Keterangan harus mengandung paling banyak %d karakter. + + Pengunggahan postingan gagal + Keterangan… + Tambahkan sebuah foto + Beralih ke karosel + Tambahkan sebuah keterangan media di sini… + Ukuran gambar nomor %1$d di album melewati ukuran maksimum yang diperbolehkan oleh instansi ini (%2$d kB tetapi batasnya %3$d kB). Anda mungkin tidak dapat mengunggahnya. + Tombol untuk memotong atau memutar gambar + Pengunduhan gagal, mohon coba lagi + Tidak ada keterangan + Anda harus memberikan izin menulis untuk mengunduh gambar! + Tidak dapat mengikuti + - +\nPengikut + AKUN-AKUN + Media CW / NSFW / Yang Disembunyikan +\n(klik untuk menampilkan) + Pengunggahan media gagal, coba lagi atau periksa kondisi jaringan + Dependensi dan lisensi + Situs web proyek: https://pixeldroid.org + PixelDroid adalah perangkat lunak yang gratis dan sumber terbuka, dilisensi dibawah GNU General Public License (versi 3 atau yang lebih baru) + Dilaporkan {gmd_check_circle} + Panda ini tidak senang. Tarik untuk memuat ulang untuk mencoba lagi. + \ No newline at end of file diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 247a9a26..5e30c24a 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -171,8 +171,14 @@ Aggiungi una descrizione dell\'immagine qui… Salva la descrizione dell\'immagine - La descrizione deve contenere al massimo %d carattere - La descrizione deve contenere al massimo %d caratteri + La descrizione deve contenere al massimo %d carattere. + La descrizione deve contenere al massimo %d caratteri. L\'API non è attivata su questa istanza. Contatta l\'amministratore per chiedergli di attivarlo. + Impossibile eliminare il post, controlla la tua connesione\? + Impossibile eliminare il post, errore %1$d + + %d Utente che stai seguendo + %d Utenti che stai seguendo + \ No newline at end of file diff --git a/app/src/main/res/values-ml/strings.xml b/app/src/main/res/values-ml/strings.xml new file mode 100644 index 00000000..3ca6e301 --- /dev/null +++ b/app/src/main/res/values-ml/strings.xml @@ -0,0 +1,124 @@ + + + ഇമേജ് വിവരണം സംരക്ഷിക്കുക + വിവരണം… + അനുമതി നിഷേധിച്ചു + പ്രവേശിക്കുന്നത് റദ്ദാക്കുക + ശരി, എന്തായാലും തുടരുക + അസാധുവായ മേഖല + ഫയൽ %1$s കണ്ടെത്തിയില്ല + കണ്ടെത്തുക + ഭാഷ + ഈ പോസ്റ്റ് ഇല്ലാതാക്കണോ\? + ഇല്ലാതാക്കൂ + തിരുത്തുക + കുറിച്ച് + PixelDroid-നെ കുറിച്ച് + അക്കൗണ്ടുകൾ + പോസ്റ്റുകൾ + തിരുത്തുക + പിന്തുടരുക + - +\nപോസ്റ്റുകൾ + തിരുത്തുക + ഒരു ഫോട്ടോ ചെർക്കൂ + മറ്റൊരു Pixelfed അക്കൗണ്ട് ചേർക്കൂ + അക്കൗണ്ട് ചേർക്കൂ + Pixelfed-ലേക്ക് കണക്റ്റുചെയ്യൂ + നിങ്ങളുടെ ഇൻസ്റ്റ്ൻസിന്റെ മേഖല + %1$s നിങ്ങളുടെ പോസ്റ്റ് ലൈക്ക് അടിച്ചു + %1$s നിങ്ങളുടെ ഷെയർ ചെയ്തു + %1$s നിങ്ങളെ സൂചിപ്പിച്ചു + %1$s നിങ്ങളെ പിന്തുടർന്നു + തീം + ക്രമീകരണങ്ങൾ + സാധാരണ + ക്രമീകരണ + PixelDroid + മീഡിയ അപ്‌ലോഡ് പൂർത്തിയായി + റിപ്പോർട്ട് ചെയ്യൂ + ലിങ്ക് പങ്കിടുക + റിപ്പോർട്ട് അയയ്ക്കാൻ കഴിഞ്ഞില്ല + പോസ്റ്റ് ഇല്ലാതാക്കാൻ കഴിഞ്ഞില്ല, നിങ്ങളുടെ കണക്ഷൻ പരിശോധിക്കുക\? + എന്തോ സംഭവിച്ചു… + പ്രൊഫൈൽ ചിത്രം + കൂടുതൽ ഓപ്ഷനുകൾ + %1$s-ന്റെ(ടെ) പോസ്റ്റ് + ഇവിടെ കാണാൻ ഒന്നുമില്ലേ! + വീണ്ടും ശ്രമിക്കുക + പ്രൊഫൈൽ തിരുത്തുക + പിന്തുടരേണ്ട + ഉപയോക്തൃനാമം ഇല്ല + ഇവിടെ കാണാൻ ഒന്നുമില്ലേ :( + + %d +\nപോസ്റ്റ് + %d +\nപോസ്റ്റുകൾ + + ശരി, അതിനായി കാത്തിരിക്കുക. + പോസ്റ്റ് അപ്‌ലോഡുചെയ്‌തു + പോസ്റ്റ് അപ്‌ലോഡ് പരാജയപ്പെട്ടു + ചിത്രം സംരക്ഷിച്ചു + ചിത്രം സംരക്ഷിക്കാനായില്ല + ഇൻസ്റ്റ്ൻസ് വിവരങ്ങൾ നേടാനായില്ല + ടോക്കൺ ലഭിക്കുന്നതിൽ പിശക് + ഉപയോക്തൃ വിവരങ്ങൾ നേടാനായില്ല + ചിത്രം പങ്കിടുക + + %d ഷെയർ + %d ഷെയറുകൾ + + + %d ലൈക്ക് + %d ലൈക്കുകൾ + + %1$s-ൽ പോസ്റ്റ് ചെയ്തത് + വിവരണം ഇല്ല + ചിത്രം വിജയകരമായി ഡൗൺലോഡുചെയ്‌തു + ഡൗൺലോഡുചെയ്യുന്നു… + ഡൗൺലോഡ് പരാജയപ്പെട്ടു, ദയവായി വീണ്ടും ശ്രമിക്കുക + ചിത്രം പങ്കിടുക… + ഗാലറിയിലേക്ക് സംരക്ഷിക്കുക… + ഗാലറി + ക്യാമറ മാറ്റുക + എടുക്കുക + ഇല്ല, എഡിറ്റ് റദ്ദാക്കുക + ദൃശ്യതീവ്രത + സാച്ചുറേഷൻ + ഫിൽട്ടറുകൾ + തെളിച്ചം + ഒരു മീഡിയ വിവരണം ഇവിടെ ചേർക്കുക… + പുറത്തു കടക്കുക + ഒരു ഇൻസ്റ്റൻസ് എന്താണ്\? + %1$s-ന്റെ(ടെ) പോൾ അവസാനിച്ചു + എന്റെ പ്രൊഫൈൽ + പോസ്റ്റ് അപ്‌ലോഡ് പിശക് + കറൗസലിലേക്ക് മാറുക + നിങ്ങളുടെ മാറ്റങ്ങൾ സംരക്ഷിക്കണോ\? + ഈ പോസ്റ്റ് ഒരു ആൽബമാണ് + ഈ പ്രവർത്തനം അനുവദനീയമല്ല + ഹാഷ്‌ടാഗുകൾ + ഇപ്പോഴും ഇമേജ് പ്രോസസ്സ് ചെയ്യുന്നു, ആദ്യം അത് പൂർത്തിയാകാൻ കാത്തിരിക്കുക! + #%1$s + സ്ഥിരസ്ഥിതി (സിസ്റ്റം പിന്തുടരുന്നു) + PixelDroid ഉപയോഗിക്കാനും ഒരു അക്കൗണ്ട് ചേർക്കാനും നിങ്ങൾ ഓൺലൈനിൽ ആയിരിക്കണം :( + ബ്രൗസർ തുറക്കാനായില്ല, നിങ്ങൾക്ക് ബ്രൗസർ ഉണ്ടോ\? + ഉറപ്പാക്കാൻ സാധിച്ചില്ലാ + ആപ്ലിക്കേഷന്റെ തീം + ലൈറ്റ് + ഡാർക്ക് + എപിഐ ഈ ഇൻസ്റ്റൻസിൽ സജീവമല്ലാ.ഇത് സജീവമാക്കാൻ നിങ്ങളുടെ അഡ്മിനിസ്ട്രേറ്ററെ ബന്ധപ്പെടുക. + ഫീഡ് ലഭ്യമാക്കാൻ സാധിച്ചില്ല + ചിത്രങ്ങൾ ഡൗൺലോഡ് ചെയ്യാൻ നിങ്ങൾ എഴുത്ത് അനുമതി നൽകണം! + ചിത്രങ്ങൾ പങ്കിടാൻ നിങ്ങൾ എഴുത്ത് അനുമതി നൽകണം! + + %d + + + ഈ സെർവറിൽ ആപ്ലിക്കേഷൻ രജിസ്റ്റർ ചെയ്യാനായില്ല + + വിവരണത്തിൽ പരമാവധി %d പ്രതീകം അടങ്ങിയിരിക്കണം. + വിവരണത്തിൽ പരമാവധി %d പ്രതീകങ്ങൾ അടങ്ങിയിരിക്കണം. + + \ No newline at end of file diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 4c669e05..d3bc7ec7 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -60,8 +60,8 @@ Beeld succesvol opgeslagen Post met succes geüpload Opnieuw proberen - {gmd_cloud_off} Het uploaden van de mediabestanden is mislukt, probeer het opnieuw of controleer de netwerkverbinding - {gmd_cloud_done} Media-upload voltooid + Het uploaden van de mediabestanden is mislukt, probeer het opnieuw of controleer de netwerkverbinding + Media-upload voltooid - \nBerichten Post-upload mislukt @@ -126,4 +126,35 @@ Dit is geen Pixelfed instantie, dus de app zou zich op onverwachte wijze kunnen gedragen. Melden De peiling van %1$s is beëindigd + Wijzigingen opslaan\? + Nee, bewerken annuleren + Kon post niet verwijderen, error %1$d + Kon post niet verwijderen, controleer je verbinding\? + + %d commentaar + %d commentaren + + + %d +\nPost + %d +\nPosts + + Je hebt meer afbeeldingen gekozen dan het maximum van jouw server (%1$s). Afbeeldingen die over dit maximum gingen zijn genegeerd. + + %d +\nVolgend + %d +\nVolgend + + + De beschrijving mag maximaal %d tekens bevatten. + De beschrijving mag maximaal %d tekens bevatten. + + + %d +\nVolger + %d +\nVolgers + \ No newline at end of file diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 46eca0e4..6a154bfa 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -1,26 +1,26 @@ Capturar - Mudar câmera + Trocar câmera CW / NSFW / Mídia oculta -\n (clicar para visualizar) - Tema da Aplicação +\n(clique para visualizar) + Tema do Aplicativo Não foi possível obter informações sobre a instância - Erro na obtenção do token + Erro ao obter a chave de acesso Não foi possível abrir um navegador, você tem algum\? Não foi possível registrar a aplicação com este servidor Domínio inválido Adicionar outra conta Pixelfed Adicionar Conta Você precisa estar conectado para poder adicionar a primeira conta e usar o PixelDroid :( - Conectar-se à Pixelfed + Conectar-se ao Pixelfed Domínio da sua instância - Nenhum comentário… + Nenhum comentário nesta publicação… Compartilhar imagem… Galeria A imagem foi transferida com sucesso - Baixando o arquivo… - O download não deu certo, por favor, tente novamente + Baixando… + O download falhou. Por favor, tente novamente Salvar na Galeria… EDITAR FILTROS @@ -29,12 +29,12 @@ BRILHO Sair O que é uma instância\? - enviar + publicar Descrição… - %1$s curtiu o seu post - %1$s compartilhou o seu post + %1$s curtiu sua postagem + %1$s compartilhou sua postagem %1$s mencionou você - %1$s começou a te seguir + %1$s seguiu você Tema Configurações Falha na autenticação @@ -42,16 +42,16 @@ Meu Perfil PixelDroid Não, cancelar edição - Ajude a traduzir o PixelDroid para a sua língua: - Apagar + Ajude a traduzir o PixelDroid para o seu idioma: + Excluir DESCOBRIR Editar - Partilhar Ligação - Reportar + Compartilhar link + Denunciar Mais opções Sobre Website do projeto: https://pixeldroid.org - Sobre PixelDroid + Sobre o PixelDroid Tentar novamente Pesquisar Editar perfil @@ -59,8 +59,10 @@ - \nSeguidores - %d Seguidor - %d Seguidores + %d +\nSeguidor + %d +\nSeguidores Submeter comentário Adicionar comentário @@ -68,33 +70,127 @@ %d comentário %d comentários - Partilhar Imagem + Compartilhar Imagem - %d Partilha - %d Partilhas + %d Compartilhamento + %d Compartilhamentos - %d Gosto - %d Gostos + %d Curtida + %d Curtidas Sem descrição Não foi possível obter feed - Botão para cortar ou rodar imagem - Pré-visualização da imagem editada - A processar imagem, espere que termine primeiro! + Botão para cortar ou girar a imagem + Pré-visualização da imagem a ser editada + Processando imagem, aguarde o término primeiro! Normal - Guardar descrição da imagem + Salvar descrição da imagem Uma das imagens na publicação Adicionar foto Erro ao publicar Publicado com sucesso Falha ao publicar - Erro de publicação: formato errado de imagem. + Erro na publicação: formato de imagem incompatível. Erro ao publicar imagem! - Imagem guardada com sucesso - Não foi possível guardar a imagem - Permissão recusada + Imagem salva com sucesso + Não foi possível salvar a imagem + Permissão negada Escuro Claro - Não foi possível obter informação do utilizador + Não foi possível obter informação do usuário + Você precisa conceder permissão de gravação para baixar imagens! + Publicado no %1$s + O campo de comentário não pode estar vazio! + Você pode ficar confuso por um campo de texto perguntando pelo domínio de sua \'instância\'. +\n +\nPixelfed é uma plataforma federada e parte do \'fediverso\', o que significa que ele pode se comunicar com outras plataformas que falam a mesma língua, como o Mastodon (veja https://joinmastodon.org). +\n +\nTambém significa que você deve escolher qual servidor ou \'instância\' do Pixelfed usar. Se você não conhece nenhum, dê uma olhada aqui: https://pixelfed.org/join +\n +\nPara mais informações sobre o Pixelfed, você pode verificar aqui: https://pixelfed.org + A enquete de %1$s finalizou + Padrão (Conforme sistema) + OK, continuar mesmo assim + Esta não parece ser uma instância Pixelfed, então o aplicativo pode quebrar de forma inesperada. + A API não está ativada nesta instância. Contate o administrador para solicitar a ativação. + Cancelar entrada + Denunciado {gmd_check_circle} + Denunciar publicação de @%1$s + Não foi possível enviar a denúncia + Mensagem opcional para moderadores/administradores + O campo de pesquisa não pode estar vazio + Publicação de %1$s + PixelDroid é um software livre e de código aberto, licenciado sob a GNU General Public License (versão 3 ou posterior) + Dependências e licenças + Nada para ver aqui! + Envio de mídia completo + PUBLICAÇÕES + Cancelar a solicitação para seguir\? + Solicitado para Seguir + Sem nome de usuário + - +\nSeguindo + - +\nPublicações + A chave de acesso é inválida + Não é possível exibir o botão de seguir + Nada para ver aqui :( + Falhou ao abrir a página de edição + + %d +\nSeguindo + %d +\nSeguindo + + + %d +\nPostagem + %d +\nPostagens + + Esta publicação é um álbum + Algo deu errado enquanto carregava + Código de erro retornado pelo servidor: %1$d + Adicione a descrição da mídia aqui… + Mudar para carrossel + Mudar para visualização em grade + Comentário: %1$s publicado! + Erro no comentário! + Você precisa conceder permissão de gravação para compartilhar imagens! + Idioma + Excluir esta publicação\? + Algo deu errado… + Foto de perfil + Seguidores de %1$s + Imagem a ser publicada + TÓPICOS + CONTAS + Deixar de seguir + Não foi possível deixar de seguir + Esta ação não é permitida + Não foi possível seguir + Comentar + + A descrição precisa ter pelo menos %d carácter. + A descrição precisa ter pelo menos %d caracteres. + + Não foi possível obter o status de seguimento + O tamanho da imagem número %1$d no álbum excede o tamanho máximo permitido pela instância (%2$d kB, mas o limite é %3$d kB). Você não poderá realizar a publicação. + Você excedeu o limite máximo que seu servidor permite (%1$s) em número de imagens. Imagens além do limite foram ignoradas. + Erro ao publicar: formato incorreto + Miniatura do filtro + Não é possível recuperar imagem após o corte + OK, aguarde um momento. + Salvar suas edições\? + Arquivo %1$s não encontrado + Não foi possível excluir a publicação, verifique sua conexão\? + Não foi possível excluir a publicação. Erro %1$d + Imagem mostrando um panda vermelho, mascote do Pixelfed, usando um telefone + Relate problemas ou contribua com o aplicativo: + O panda não está feliz. Puxe para atualizar e tentar novamente. + As descobertas não carregam infinitamente. Puxe para atualizar para outras imagens. + Abrir o menu lateral + %1$s está seguindo + Envio de mídia falhou. Tente novamente ou verifique as condições de conectividade \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 278d24ef..579f4fff 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -3,12 +3,12 @@ Не удалось авторизоваться Ошибка получения токена Настройки - Тема Приложения + Тема приложения Тема - %1$s подписался(-лась) на вас + %1$s подписан(а) на вас %1$s упомянул(а) вас - %1$s поделился(-лась) вашим постом - отправить + %1$s поделился(ась) вашим постом + пост Выйти ЯРКОСТЬ Что такое инстанс\? @@ -25,17 +25,17 @@ Домен вашего инстанса Подключение к Pixelfed PixelDroid - Мой профиль + Мой Профиль Настройки - Некорректный домен + Некоректный домен Не удалось запустить браузер, есть ли он у вас\? - %1$s оценил(а) ваш пост + %1$s оценил(и) ваш пост Описание… - Сохранение не удалось, попробуйте ещё раз + Загрузка не удалась, попробуйте ещё раз Поделиться изображением… - Вам необходимо быть в сети что бы добавить аккаунт и использовать PixelDroid :( - CW / NSFW / Скрытое медиа -\n(кликните что бы показать 18+) + Вам необходимо быть в сети чтобы добавить аккаунт и использовать PixelDroid :( + CW / NSFW / Медиа для 18+ +\n(кликните что бы показать) Не удалось зарегистрировать приложение на этом инстансе Сделать снимок Добавить другой аккаунт Pixelfed @@ -44,9 +44,9 @@ Комментарий Комментарий: %1$s опубликован! Ошибка комментария! - Поделиться Изображением + Поделиться изображением Вы должны дать разрешение на запись для загрузки изображений! - Вы должны дать разрешение на запись чтобы делиться изображениями! + Вы должны дать разрешение на запись чтобы делиться фотографиями! Комментарий не может быть пустым! Опубликовано в %1$s Нет описания @@ -64,9 +64,9 @@ Отказано в доступе Тёмная Светлая - По умолчанию (Как в системе) + По умолчанию (как в системе) Не удалось получить статус подписки - Подписка не удалась + Не удалась подписаться Это действие недопустимо Не удалось отписаться Токен доступа недействителен @@ -85,15 +85,15 @@ ХЭШТЕГИ Не удалось отобразить кнопку подписки Изображение, которое будет опубликовано - {gmd_cloud_done} Загрузка медиа завершена - Ещё раз - {gmd_cloud_off} Загрузка медиа не удалась, попробуйте снова или проверьте сеть + Загрузка медиа завершена + Повторить + Ошибка загрузки медиа, попробуйте ещё раз или проверьте состояние сети Здесь нечего смотреть! Не удалось получить изображение после обрезки - Ок, подожду. + Ок, ожидайте. Изображение обрабатывается, пожалуйста, ожидайте! Открыть меню навигации - Эта панда несчастлива. Потяни, чтобы обновить. + Панде грустно. Потяните, чтобы обновить. Что-то пошло не так… ОБЗОР Изображение профиля @@ -108,18 +108,18 @@ Поисковый запрос не может быть пустым %1$s подписок %1$s подписчиков - %1$s пост + Пост %1$s О приложении - PixelDroid это свободное ПО с открытым исходным кодом, выпускаемое под лицензией GNU General Public License (версии 3 или новее) + PixelDroid это свободное ПО с открытым исходным кодом, выпускаемое под лицензией GNU General Public License (версии 3 и выше) Сайт проекта: https://pixeldroid.org Зависимости и лицензии О PixelDroid Отписаться Добавить фото - %1$s завершил опрос - Отмена входа + %1$s опрос завершён + Отменить вход OK, продолжить всё равно - Это не похоже на инстанс Pixelfed, приложение может работать нестабильно. + Это не похоже на инстанс Pixelfed, приложение может работать с ошибками. Сохранить описание изображения Одно из изображений в посте Невозможно получить информацию о пользователе @@ -129,8 +129,8 @@ Описание должно содержать максимум %d символов. Описание должно содержать максимум %d символов. - Нет, отменить редактирование - Сохранить ваши редактирования\? + Нет, отменить изменения + Сохранить изменения\? Изображение красной панды, талисман Pixelfed , использующей телефон Сообщайте о проблемах или вносите свой вклад в приложение: Помогите перевести PixelDroid на ваш язык: @@ -138,25 +138,37 @@ Удалить этот пост\? Удалить - %d Подписка - %d Подписки - %d Подписок - %d Подписок + %d +\nПодписка + %d +\nПодписки + %d +\nПодписок + %d +\nПодписок - %d Подписчик - %d Подписчика - %d Подписчиков - %d Подписчиков + %d +\nПодписчик + %d +\nПодписчика + %d +\nПодписчиков + %d +\nПодписчиков - %d Пост - %d Поста - %d Постов - %d Постов + %d +\nПост + %d +\nПоста + %d +\nПостов + %d +\nПостов Этот пост в альбоме - Отправить комментарий + Предложить комментарий Добавить комментарий %d комментарий @@ -178,8 +190,8 @@ Предварительный просмотр редактируемого изображения Фильтр миниатюр - Добавить описание медиа файла здесь… - Показывать в режиме «карусели» + Добавьте описание медиа файла здесь… + Показывать в режиме «карусель» Вас может смутить текстовое поле, запрашивающее доменное имя вашего \'инстанса\'. \n \nPixelfed это федеративная платформа и часть \"федиверса\", что означает, что она может общаться с другими платформами, говорящими на том же языке, как например Mastodon (см. https://joinmastodon.org). @@ -188,5 +200,18 @@ \n \nДополнительную информации о Pixelfed вы можете посмотреть здесь: https://pixelfed.org Кнопка для обрезки или поворота изображения - Переключить в виде сетки + Переключить в вид сетки + Обзор не может загружаться бесконечно. Потяните, чтобы обновить другие изображения. + Отменить запрос на подписку\? + Подписаться на запрос + Вы выбрали большее изображений, чем разрешено вашим сервером (%1$s). Изображения сверх установленного лимита игнорируются. + На этом инстансе API не активирован. Свяжитесь с вашим администратором для его активации. + Не удалось удалить пост, проверить подключение\? + Ошибка при удалении поста %1$d + Здесь ничего нет :( + Не удалось открыть страницу редактирования + Код ошибки, возвращенный сервером: %1$d + Размер изображения в альбоме превышает максимальный размер в %1$d разрешённый инстансом (%2$d Кбайт, тогда как лимит установлен в %3$d Кбайт). По всей вероятности вы не сможете загрузить его. + #%1$s + Файл %1$s не найден \ No newline at end of file diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index e47327bc..d69a7642 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -43,8 +43,8 @@ 无法获取实例信息 重试 待发布的图像 - {gmd_cloud_off} 媒体上传失败,请重试或检查网络状况 - {gmd_cloud_done} 媒体已上传 + 媒体上传失败,请重试或检查网络状况 + 已完成媒体上传 标签 帐户 帖文 @@ -90,14 +90,14 @@ 深色 这里什么也没有! 图像裁剪后无法恢复 - 好的 + 好的,等一下。 图像仍在处理中,请先等待完成! 帖文中的一张图片 添加照片 %1$s投票已经结束 取消登录 了解,请继续 - 这似乎不是一个 Pixelfed 实例,可能会导致应用意外退出 + 这似乎不是一个 Pixelfed 实例,因此该应用可能以意想不到的方式崩溃。 无法获得用户信息 关于 项目主页:https://pixeldroid.org @@ -105,4 +105,83 @@ 关于 PixelDroid 分享链接 删除 + 请求你的 \'实例\' 域名的文本框可能让你觉得困惑。 +\n +\nPixelfed是一个联合平台,是“fediverse”的一部分,这意味着它可以与其他使用相同语言的平台进行交流,就像 Mastodon (见 https://joinmastodon.org) +\n +\n这也意味着你必须选择 Pixelfed 使用哪个服务器或“实例”。如果你不清楚,你可以看这里:https://pixelfed.org/join +\n +\n关于 Pixelfed 的更多信息,请见此处:https://pixelfed.org + 此实例上未激活 API。联系管理员,请他们激活它。 + 法删除帖子,请检查你的连接\? + 无法删除帖子,错误 %1$d + 图片显示的是一只小熊猫,Pixelfed的吉祥物,正在用手机 + 报告问题或为这个应用程序作贡献: + 帮助将 PixelDroid 翻译到你的语言: + 语言 + 删除这则帖子? + 这只熊猫不高兴。下拉刷新以再次尝试。 + 出错了… + Discover 不会无限加载。下拉来刷新获取其他图像。 + 发现 + 打开抽屉按钮 + 个人资料图片 + 编辑 + 无法发送报告 + 已报告 {gmd_check_circle} + 报告 @%1$s 的帖子 + 管理员的可选消息 + 报告 + 更多选项 + 搜索查询不能为空 + %1$s 的关注 + %1$s 的关注者 + %1$s 的帖子 + PixelDroid 是自由开源软件,使用 GNU 通用公共许可证 (版本3或更高版本) + 依赖和许可证 + 取消这个关注请求? + 已请求关注 + 这儿没什么可看的 :( + 未能打开编辑页面 + 这个帖子是一个相册 + 提交评论 + 添加一条评论 + + %d 条评论 + + 不,取消编辑 + 保存你的编辑? + 裁剪或旋转图片的按钮 + 被编辑图片的预览 + 过滤器的缩略图 + 服务器返回了错误码:%1$d + 相册中 %1$d 号图片的尺寸超出了实例允许的最大尺寸 (图片大小为 %2$d kb 而上限为 %3$d kb)。你可能无法上传这张图片。 + 你选择的图片数超出了你服务器允许的最大数目 (%1$s)。超出上限的图像已被忽略。 + 在此处添加一个媒体描述… + 保存图片描述 + 切换到旋转视图 + 切换到网格视图 + + %d +\n关注账户 + + + %d +\n关注者 + + + %d +\n帖子 + + + %d 次分享 + + + %d 个赞 + + + 描述必须最多包含 %d 个字符。 + + 文件 %1$s 未找到 + #%1$s \ No newline at end of file diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 852df30e..8e52a0d3 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -22,10 +22,13 @@ Euskara English فارسی + Suomi Français Gaeilge + bahasa Indonesia Italiano 日本語 + മലയാളം Nederlands Polski Português (Brasil) @@ -45,10 +48,13 @@ eu en fa + fi fr gl + id it ja + ml nl pl pt-br diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 35dbea71..34cacd40 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,7 +1,12 @@ + PixelDroid + + My Profile + + Settings "Invalid domain" "Could not register the application with this server" @@ -14,16 +19,35 @@ "OK, continue anyway" "Cancel logging in" Settings - + + Application Theme + + Theme + + Default (Follows system) + + Light + + Dark + + %1$s followed you + + %1$s mentioned you + + %1$s shared your post + + %1$s liked your post + + "%1$s's poll has ended" @@ -152,6 +176,8 @@ For more info about Pixelfed, you can check here: https://pixelfed.org" No Username Follow Unfollow + Follow Requested + Cancel the follow request? Edit profile Search @@ -161,9 +187,9 @@ For more info about Pixelfed, you can check here: https://pixelfed.org" CW / NSFW / Hidden Media\n (click to show) - {gmd_cloud_done} Media upload completed + Media upload completed - {gmd_cloud_off} Media upload failed, try again or check network conditions + Media upload failed, try again or check network conditions Image that is being posted Retry Nothing to see here! @@ -174,6 +200,7 @@ For more info about Pixelfed, you can check here: https://pixelfed.org" About %1$s\'s post %1$s\'s followers + #%1$s %1$s\'s follows Search query can\'t be empty More options @@ -188,6 +215,7 @@ For more info about Pixelfed, you can check here: https://pixelfed.org" Profile picture Open drawer menu DISCOVER + Discover doesn\'t load infinitely. Pull to refresh for other images. Something went wrong… This panda is not happy. Pull to refresh to try again. Delete @@ -198,4 +226,7 @@ For more info about Pixelfed, you can check here: https://pixelfed.org" Image showing a red panda, Pixelfed\'s mascot, using a phone Could not delete the post, error %1$d Could not delete the post, check your connection? + + + File %1$s was not found \ No newline at end of file diff --git a/app/src/main/res/xml/file_paths.xml b/app/src/main/res/xml/file_paths.xml index c02d48ab..509c1076 100644 --- a/app/src/main/res/xml/file_paths.xml +++ b/app/src/main/res/xml/file_paths.xml @@ -1,4 +1,4 @@ - + diff --git a/app/src/main/res/xml/root_preferences.xml b/app/src/main/res/xml/root_preferences.xml index f3e04443..298a62a6 100644 --- a/app/src/main/res/xml/root_preferences.xml +++ b/app/src/main/res/xml/root_preferences.xml @@ -26,7 +26,7 @@ android:summary="@string/about_pixeldroid" app:icon="@drawable/info_black_24dp"> + android:targetPackage="@string/application_id" + android:targetClass="org.pixeldroid.app.settings.AboutActivity"/> diff --git a/app/src/test/java/com/h/pixeldroid/APIUnitTest.kt b/app/src/test/java/org/pixeldroid/app/APIUnitTest.kt similarity index 99% rename from app/src/test/java/com/h/pixeldroid/APIUnitTest.kt rename to app/src/test/java/org/pixeldroid/app/APIUnitTest.kt index 560839d8..cb683510 100644 --- a/app/src/test/java/com/h/pixeldroid/APIUnitTest.kt +++ b/app/src/test/java/org/pixeldroid/app/APIUnitTest.kt @@ -1,10 +1,9 @@ -package com.h.pixeldroid +package org.pixeldroid.app import com.github.tomakehurst.wiremock.client.WireMock.* import com.github.tomakehurst.wiremock.junit.WireMockRule -import com.h.pixeldroid.utils.api.PixelfedAPI -import com.h.pixeldroid.utils.api.objects.* -import io.reactivex.Single +import org.pixeldroid.app.utils.api.PixelfedAPI +import org.pixeldroid.app.utils.api.objects.* import kotlinx.coroutines.runBlocking import org.junit.Assert.assertEquals import org.junit.Rule @@ -91,7 +90,7 @@ class APIUnitTest { statuses = PixelfedAPI.createFromUrl("http://localhost:8089") .timelinePublic(null, null, null, null, null) statusesHome = PixelfedAPI.createFromUrl("http://localhost:8089") - .timelineHome("abc", null, null, null,null, null) + .timelineHome(null, null, null, null, null) } @@ -141,7 +140,7 @@ class APIUnitTest { ))) val OAUTH_SCHEME = "oauth2redirect" val SCOPE = "read write follow" - val PACKAGE_ID = "com.h.pixeldroid" + val PACKAGE_ID = "org.pixeldroid.app" val token: Token = runBlocking { PixelfedAPI.createFromUrl("http://localhost:8089") diff --git a/app/src/test/java/com/h/pixeldroid/PostUnitTest.kt b/app/src/test/java/org/pixeldroid/app/PostUnitTest.kt similarity index 97% rename from app/src/test/java/com/h/pixeldroid/PostUnitTest.kt rename to app/src/test/java/org/pixeldroid/app/PostUnitTest.kt index 73d2e704..e0d34fd3 100644 --- a/app/src/test/java/com/h/pixeldroid/PostUnitTest.kt +++ b/app/src/test/java/org/pixeldroid/app/PostUnitTest.kt @@ -1,6 +1,6 @@ -package com.h.pixeldroid +package org.pixeldroid.app -import com.h.pixeldroid.utils.api.objects.* +import org.pixeldroid.app.utils.api.objects.* import org.junit.Assert import org.junit.Test import java.text.SimpleDateFormat diff --git a/build.gradle b/build.gradle index 5b41220b..1f7bac9a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,21 +1,13 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.4.31' + ext.kotlin_version = '1.5.20' repositories { google() mavenCentral() - jcenter { - content { - // org.jetbrains.trove4j is only available in JCenter - //TODO remove JCenter repo: - // see issue https://gitlab.shinice.net/pixeldroid/PixelDroid/-/issues/278 - includeGroup("org.jetbrains.trove4j") - } - } } dependencies { - classpath 'com.android.tools.build:gradle:4.1.3' + classpath 'com.android.tools.build:gradle:4.2.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong @@ -34,11 +26,6 @@ allprojects { //TODO remove JCenter repo: // see issue https://gitlab.shinice.net/pixeldroid/PixelDroid/-/issues/278 includeGroup("info.androidhive") - - // org.jetbrains.trove4j is only available in JCenter - //TODO remove JCenter repo: - // see issue https://gitlab.shinice.net/pixeldroid/PixelDroid/-/issues/278 - includeGroup("org.jetbrains.trove4j") } } } diff --git a/fastlane/metadata/android/en-US/changelogs/2.txt b/fastlane/metadata/android/en-US/changelogs/2.txt new file mode 100644 index 00000000..41fd0bd9 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/2.txt @@ -0,0 +1,7 @@ +* Translation updates: new strings and updates to other strings. Thanks translators ❤️! Go to our weblate if you want to help with the translation into your language. + +* #️⃣ Hashtag support. You can now browse hashtags, instead of just showing a toast message 😜 + +* Click tab to scroll to top. No more furious scrolling to get back to the top. Just click the tab you're in again and it will scroll up :) + +* Try to fix some bug that made the app crash. Thanks a lot everyone for your crash reports! ❤️ diff --git a/fastlane/metadata/android/en-US/changelogs/3.txt b/fastlane/metadata/android/en-US/changelogs/3.txt new file mode 100644 index 00000000..715ba76a --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/3.txt @@ -0,0 +1,7 @@ +* Add language (Malayalam) + +* Bug fix for some bad API responses + +* Update dependencies + +* Update translations \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/full_description.txt b/fastlane/metadata/android/en-US/full_description.txt index 41ff5591..4031a22c 100644 --- a/fastlane/metadata/android/en-US/full_description.txt +++ b/fastlane/metadata/android/en-US/full_description.txt @@ -1,3 +1,11 @@ PixelDroid is a Free and Open Source Android client for Pixelfed, the federated image sharing platform. -One may upload new posts, search or interact with others inluding liking and sharing others' posts as well as leaving comments under them. +Browse feeds and profiles, upload new posts, discover posts, interact with others on the fediverse. + +• Multi-Account support +• Dark and light themes +• Apply filters, crop, change brightness/contrast/saturation +• Takes into account the configuration of your Pixelfed server +• 100% Free and Open Source software. No proprietary dependencies. + +Check out https://pixelfed.org to learn more about Pixelfed. diff --git a/fastlane/metadata/android/en-US/images/featureGraphic.png b/fastlane/metadata/android/en-US/images/featureGraphic.png new file mode 100644 index 00000000..b25ca7bc Binary files /dev/null and b/fastlane/metadata/android/en-US/images/featureGraphic.png differ diff --git a/fastlane/metadata/android/fa/changelogs/2.txt b/fastlane/metadata/android/fa/changelogs/2.txt new file mode 100644 index 00000000..6ff36310 --- /dev/null +++ b/fastlane/metadata/android/fa/changelogs/2.txt @@ -0,0 +1,7 @@ +* به‌روزرسانی‌های ترجمه: رشته‌های جدید و به‌روزرسانی‌های جدید دیگر رشته‌ها. با سپاس از مترجمین ❤️! برای کمک به ترجمه، به وب‌لیت ما مراجعه کنید. + +* #️⃣پشتیبانی از هشتگ: اکنون می‌توانید فراتر از نمایش یک پیام 😜، هشتگ‌ها را مرور کنید. + +* پیمایش به بالا با کلیک روی برگه: به جای کلی پیمایش تا بالای صفحه کافی است مجددا روی برگه کلیک کنید تا شما را به بالای صفحه ببرد :) + +* تلاش برای رفع مشکلات منجر به فروپاشی: با سپاس فراوان از همه کسانی که مشکلات مربوط به فروپاشی‌ها را گزارش کردید! ❤️ diff --git a/fastlane/metadata/android/fa/changelogs/3.txt b/fastlane/metadata/android/fa/changelogs/3.txt new file mode 100644 index 00000000..1dbf4b3d --- /dev/null +++ b/fastlane/metadata/android/fa/changelogs/3.txt @@ -0,0 +1,7 @@ +* افزودن زبان (مالایالم) + +* رفع مشکل پاسخ بد API + +* به‌روزرسانی وابستگی‌ها + +* به‌روزرسانی ترجمه‌ها diff --git a/fastlane/metadata/android/fa/full_description.txt b/fastlane/metadata/android/fa/full_description.txt new file mode 100644 index 00000000..54369cbb --- /dev/null +++ b/fastlane/metadata/android/fa/full_description.txt @@ -0,0 +1,11 @@ +پیکسل‌دروید، کارخواه اندرویدی آزاد و متن‌باز برای سکوی فدرال هم‌رسانی تصویر پیکسل‌فد است. + +بین نمایه‌ها و خوراک‌ها بچرخید، مطلب منتشر کنید، فرسته‌های دیگران را کاوش کنید و با دیگر افراد روی فدیورس تعامل داشته باشید. + +• پشتیبانی از چند حساب +• پوسته روشن و تاریک +• اعمال پالایه‌ها، برش، تغییر روشنایی/تضاد/اشباع +• در نظر گرفتن پیکربندی حساب روی کارساز پیکسل‌فد +• تماما یک نرم‌افزار آزاد و متن‌باز و فاقد هیچ گونه وابستگی انحصاری + +برای دانستن بیشتر https://pixelfed.org را ببیند. diff --git a/fastlane/metadata/android/fa/short_description.txt b/fastlane/metadata/android/fa/short_description.txt new file mode 100644 index 00000000..f5d40dad --- /dev/null +++ b/fastlane/metadata/android/fa/short_description.txt @@ -0,0 +1 @@ +کارخواهی برای پیکس‌فد، سکوی فدرال هم‌رسانی تصویر diff --git a/fastlane/metadata/android/fa/title.txt b/fastlane/metadata/android/fa/title.txt new file mode 100644 index 00000000..c9a5a090 --- /dev/null +++ b/fastlane/metadata/android/fa/title.txt @@ -0,0 +1 @@ +پیکسل‌دروید diff --git a/fastlane/metadata/android/fi/changelogs/2.txt b/fastlane/metadata/android/fi/changelogs/2.txt new file mode 100644 index 00000000..dec7f5c4 --- /dev/null +++ b/fastlane/metadata/android/fi/changelogs/2.txt @@ -0,0 +1,7 @@ +* Käännöspäivitykset: uusia tekstejä ja päivityksiä vanhoihin. Kiitos kääntäjille ❤️! Mene meidän weblateen, jos haluat auttaa kääntämisessä omalle kielellesi. + +* #️⃣ Hastag-tuki. Voit nyt selata hastageja, sen sijaan että näytetään vain toast-viesti 😜 + +* Napauta välilehteä palataksesi ylös. Ei enään raivostuttavaa vierittämistä. Napauta vain uudelleen välilehteä, jossa olet, ja se vie sinut takaisin ylös :) + +* Korjattu sovelluksen kaatavia virheitä. Kiitos kaikille kaatumisraporteista! ❤️ diff --git a/fastlane/metadata/android/fi/full_description.txt b/fastlane/metadata/android/fi/full_description.txt new file mode 100644 index 00000000..4fa0f365 --- /dev/null +++ b/fastlane/metadata/android/fi/full_description.txt @@ -0,0 +1,11 @@ +PixelDroid on vapaa ja avoimen lähdekoodin Android-asiakas Pixelfedille, hajautetulle kuvanjakoalustalle. + +Selaa feedejä ja profiileja, tee julkaisuja, löydä julkaisuja ja ole vuorovaikutuksessa muiden kanssa fediversessa. + +• Usean tilin tuki +• Tumma ja vaalea teema +• Lisää suodattimia, rajaa, muuta kirkkautta/kontrastia/värikylläisyyttä +• Ottaa huomioon Pixelfed-instanssin määritykset +• 100% vapaa ja avoimen lähdekoodin ohjelmisto. Ei suljettuja riippuvuuksia. + +Oppiaksesi lisää Pixelfedistä, katso https://pixelfed.org diff --git a/fastlane/metadata/android/fi/short_description.txt b/fastlane/metadata/android/fi/short_description.txt new file mode 100644 index 00000000..e44a7b97 --- /dev/null +++ b/fastlane/metadata/android/fi/short_description.txt @@ -0,0 +1 @@ +Asiakas Pixelfedille, hajautetulle kuvanjakoalustalle diff --git a/fastlane/metadata/android/fi/title.txt b/fastlane/metadata/android/fi/title.txt new file mode 100644 index 00000000..f51fce80 --- /dev/null +++ b/fastlane/metadata/android/fi/title.txt @@ -0,0 +1 @@ +PixelDroid diff --git a/fastlane/metadata/android/zh-CN/full_description.txt b/fastlane/metadata/android/zh-CN/full_description.txt new file mode 100644 index 00000000..3a0de43f --- /dev/null +++ b/fastlane/metadata/android/zh-CN/full_description.txt @@ -0,0 +1,11 @@ +PixelDDroid 是联合图片共享平台 Pixelfed 的一款自由和开源的安卓客户端。 + +浏览 feeds 和个人资料页,上传新帖子,发现帖子,与 fediver 上的其他人互动。 + +• 多账户支持 +• 深色和浅色主题 +• 应用滤镜,裁剪,改变亮度/对比度/饱和度 +• 允许使用自托管 Pixelfed 服务器 +• 100% 自由和开源软件。不依赖专有软件。 + +查看 https://pixelfed.org 了解更多关于 Pixelfed 的信息。 diff --git a/fastlane/metadata/android/zh-CN/short_description.txt b/fastlane/metadata/android/zh-CN/short_description.txt new file mode 100644 index 00000000..e563692e --- /dev/null +++ b/fastlane/metadata/android/zh-CN/short_description.txt @@ -0,0 +1 @@ +联合图片共享平台 Pixelfed 的客户端 diff --git a/fastlane/metadata/android/zh-CN/title.txt b/fastlane/metadata/android/zh-CN/title.txt new file mode 100644 index 00000000..f51fce80 --- /dev/null +++ b/fastlane/metadata/android/zh-CN/title.txt @@ -0,0 +1 @@ +PixelDroid diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b4f9e8a4..f4cbfee3 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ -#Fri Aug 21 12:53:39 CEST 2020 +#Tue Apr 20 12:38:34 CEST 2021 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +distributionSha256Sum=81003f83b0056d20eedf48cddd4f52a9813163d4ba185bcf8abd34b8eeea4cbd