diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..1d1fe94 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +Dockerfile \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..8af2caf --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,163 @@ +stages: + - environment + - build + - test + - internal + - alpha + - beta + - production + - stop + +.updateContainerJob: + image: docker:stable + stage: environment + services: + - docker:dind + script: + - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY + - docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG || true + - docker build --cache-from $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG -t $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG . + - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG + tags: + - shell + +updateContainer: + extends: .updateContainerJob + only: + changes: + - Dockerfile + +ensureContainer: + extends: .updateContainerJob + allow_failure: true + before_script: + - "mkdir -p ~/.docker && echo '{\"experimental\": \"enabled\"}' > ~/.docker/config.json" + - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY + # Skip update container `script` if the container already exists + # via https://gitlab.com/gitlab-org/gitlab-ce/issues/26866#note_97609397 -> https://stackoverflow.com/a/52077071/796832 + - docker manifest inspect $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG > /dev/null && exit || true + +.build_job: + image: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG + stage: build + before_script: + # We store this binary file in a variable as hex with this command, `xxd -p android-signing-keystore.jks > jks.txt` (remove all \n) + # Then we convert the hex back to a binary file + - pwd + - echo "$signing_jks_file_hex" | xxd -r -p - > android-signing-keystore.jks + - md5sum android-signing-keystore.jks + # get next version from latest changelog + - "export VERSION_CODE=`ls -f ./fastlane/metadata/android/en-US/changelogs | cut -d_ -f3 | sort -n | tail -1 | rev | cut -c5- | rev` && echo $VERSION_CODE" + # We add 200 to get this high enough above current versionCodes that are published + # - "export VERSION_CODE=$((200 + $CI_PIPELINE_IID)) && echo $VERSION_CODE" + - "export VERSION_SHA=`echo ${CI_COMMIT_SHA:0:8}` && echo $VERSION_SHA" + - "export VERSION_NAME=${VERSION_CODE:0:1}.${VERSION_CODE:1:1}.${VERSION_CODE:2} && echo $VERSION_NAME" + after_script: + - rm -f android-signing-keystore.jks || true + artifacts: + paths: + - app/build/outputs + tags: + - docker + +buildDebug: + extends: .build_job + script: + - bundle exec fastlane buildDebug + +buildRelease: + extends: .build_job + script: + - bundle exec fastlane buildRelease + environment: + name: production + only: + - /^v[0-9]*\.[0-9]*\.[0-9]*$/i + except: + - branches + +testDebug: + image: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG + stage: test + dependencies: + - buildDebug + script: + - bundle exec fastlane test + tags: + - docker + +publishGithub: + image: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG + stage: internal + dependencies: + - buildRelease + when: manual + script: + - "export VERSION_CODE=`ls -f ./fastlane/metadata/android/en-US/changelogs | cut -d_ -f3 | sort -n | tail -1 | rev | cut -c5- | rev` && echo $VERSION_CODE" + - "export VERSION_SHA=`echo ${CI_COMMIT_SHA:0:8}` && echo $VERSION_SHA" + - "export VERSION_NAME=${VERSION_CODE:0:1}.${VERSION_CODE:1:1}.${VERSION_CODE:2} && echo $VERSION_NAME" + - ci-scripts/make-github-release.sh + tags: + - docker + only: + - /^v[0-9]*\.[0-9]*\.[0-9]*$/i + +publishInternal: + image: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG + stage: internal + dependencies: + - buildRelease + when: manual + before_script: + - echo $google_play_service_account_api_key_json > ../google_play_api_key.json + - md5sum /builds/sschueller/google_play_api_key.json + after_script: + - rm -f ../google_play_api_key.json + script: + - bundle exec fastlane internal + tags: + - docker + only: + - /^v[0-9]*\.[0-9]*\.[0-9]*$/i + +.promote_job: + image: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG + when: manual + dependencies: [] + before_script: + - echo $google_play_service_account_api_key_json > ../google_play_api_key.json + - md5sum ../google_play_api_key.json + after_script: + - rm -f ../google_play_api_key.json + +promoteAlpha: + extends: .promote_job + stage: alpha + script: + - bundle exec fastlane promote_internal_to_alpha + tags: + - docker + only: + - /^v[0-9]*\.[0-9]*\.[0-9]*$/i + +promoteBeta: + extends: .promote_job + stage: beta + script: + - bundle exec fastlane promote_alpha_to_beta + tags: + - docker + only: + - /^v[0-9]*\.[0-9]*\.[0-9]*$/i + +promoteProduction: + extends: .promote_job + stage: production + # We only allow production promotion on `master` because + # it has its own production scoped secret variables + only: + - /^v[0-9]*\.[0-9]*\.[0-9]*$/i + script: + - bundle exec fastlane promote_beta_to_production + tags: + - docker \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index f57e087..4c29d77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,52 @@ +### Version 1.0.51 Tag: v1.0.51 (2021-01-14) + - fixed default app language on first start (@kosharskiy) + - Settings screen translations uk and ru languages (@kosharskiy) + - cleanup app/build.gradle file (@kosharskiy) + - fixed video meta data display issue (@kosharskiy) + - updated translations + +### Version 1.0.50 Tag: v1.0.50 (2020-11-22) + - add support for disabling SSL + - translations + +### Version 1.0.49 Tag: v1.0.49 (2020-09-26) + - add support of hypertext redirection in description (@freeboub) + - various crash fixes (@freeboub) + - avoid going to pip when leaving the app due to share button (@freeboub) + - Add ability to filter server list (@freeboub) + - Refactor Toast error management to split network error (@freeboub) + - keep video aspect ratio for pip (@freeboub) + - navigation bar was not restored when leaving landscape mode (@freeboub) + +### Version 1.0.48 Tag: v1.0.48 (2020-09-26) + - f-droid release to fix auto deployment + +### Version 1.0.47 Tag: v1.0.47 (2020-07-10) + * Authentication refresh + +### Version 1.0.46 Tag: v1.0.46 (2020-07-08) + * Revert broken auth + +### Version 1.0.45 Tag: v1.0.45 (2020-07-08) + * Added token refresh + +### Version 1.0.44 Tag: v1.0.44 (2020-07-05) + * Completed implementation of Likes & Dislikes (@Poslovitch) + * Added preview of the current playback speed and video quality in the VideoOptionsFragment (@Poslovitch) + * Lots of code cleanup + * Various translations + +### Version 1.0.43 Tag: v1.0.43 (2020-07-04) + * Fix back button issue + +### Version 1.0.42 Tag: v1.0.42 (2020-07-04) + * Added appbar at the top of the SettingsActivity (@Poslovitch) + * Improved and added some French translations (@Poslovitch) + * Removed translations for untranslatable strings (@Poslovitch) + * Add stop button to expanded notification, and stop and switch to audio in video window (@dhk2) + * More data in Server search + * VideoList timestamp fix + ### Version 1.0.41 Tag: v1.0.41 (2020-06-28) * Floating window player controls fix (@dhk2) * Updated app icons diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000..6aedc74 --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,16 @@ +## Internal deployment notes + + 1. merge pull-requests on github into develop + 2. Locally switch to develop + 3. Pull github develop + 4. Pull weblate develop + 5. Add change logs (fastlane/metadata/android/en-US/changelogs/XXX.txt) + 6. Run ci-script/update-changelog.sh + 7. Push to gitlab + 8. Merge request into master and merge + 9. Add Release Tag on master branch + 10. Release to play store + 11. Wait for gitlab -> github sync + 12. Run publishGithub + + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..24e2d5c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,45 @@ +FROM gradle:6.1.1-jdk8 + +ENV ANDROID_SDK_URL https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip +ENV ANDROID_SDK_CHECKSUM 444e22ce8ca0f67353bda4b85175ed3731cae3ffa695ca18119cbacef1c1bea0 +ENV ANDROID_BUILD_TOOLS_VERSION 29.0.3 +ENV ANDROID_HOME /usr/local/android-sdk-linux +ENV ANDROID_VERSION 29 +ENV PATH ${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools + +RUN mkdir "$ANDROID_HOME" .android && \ + cd "$ANDROID_HOME" && \ + curl -o sdk.zip $ANDROID_SDK_URL && \ + echo "${ANDROID_SDK_CHECKSUM} sdk.zip" | sha256sum -c - && \ + unzip sdk.zip && \ + rm sdk.zip + +RUN yes | ${ANDROID_HOME}/tools/bin/sdkmanager --licenses +RUN $ANDROID_HOME/tools/bin/sdkmanager --update +RUN $ANDROID_HOME/tools/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" \ + "platforms;android-${ANDROID_VERSION}" \ + "platform-tools" + +# install OS packages +RUN apt-get --quiet update --yes + +# Installing build tools +RUN apt-get update && \ + apt-get install -y \ + build-essential \ + ruby \ + jq \ + ruby-dev + +# We use this for xxd hex->binary +RUN apt-get --quiet install --yes vim-common + +# install FastLane +COPY Gemfile.lock . +COPY Gemfile . +RUN gem update --system 3.0.8 # https://github.com/rubygems/rubygems/issues/3068 +RUN gem install bundler +RUN bundle install + +# at least 1.5G memory is required for the gitlab runner to succeed +#RUN echo "org.gradle.jvmargs=-Xmx1536m" >> local.properties \ No newline at end of file diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..7a118b4 --- /dev/null +++ b/Gemfile @@ -0,0 +1,3 @@ +source "https://rubygems.org" + +gem "fastlane" diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6e7ebae --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,178 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.2) + addressable (2.7.0) + public_suffix (>= 2.0.2, < 5.0) + atomos (0.1.3) + aws-eventstream (1.1.0) + aws-partitions (1.353.0) + aws-sdk-core (3.104.3) + aws-eventstream (~> 1, >= 1.0.2) + aws-partitions (~> 1, >= 1.239.0) + aws-sigv4 (~> 1.1) + jmespath (~> 1.0) + aws-sdk-kms (1.36.0) + aws-sdk-core (~> 3, >= 3.99.0) + aws-sigv4 (~> 1.1) + aws-sdk-s3 (1.76.0) + aws-sdk-core (~> 3, >= 3.104.1) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.1) + aws-sigv4 (1.2.1) + aws-eventstream (~> 1, >= 1.0.2) + babosa (1.0.3) + claide (1.0.3) + colored (1.2) + colored2 (3.1.2) + commander-fastlane (4.4.6) + highline (~> 1.7.2) + declarative (0.0.20) + declarative-option (0.1.0) + digest-crc (0.6.1) + rake (~> 13.0) + domain_name (0.5.20190701) + unf (>= 0.0.5, < 1.0.0) + dotenv (2.7.6) + emoji_regex (3.0.0) + excon (0.76.0) + faraday (1.0.1) + multipart-post (>= 1.2, < 3) + faraday-cookie_jar (0.0.6) + faraday (>= 0.7.4) + http-cookie (~> 1.0.0) + faraday_middleware (1.0.0) + faraday (~> 1.0) + fastimage (2.2.0) + fastlane (2.155.3) + CFPropertyList (>= 2.3, < 4.0.0) + addressable (>= 2.3, < 3.0.0) + aws-sdk-s3 (~> 1.0) + babosa (>= 1.0.3, < 2.0.0) + bundler (>= 1.12.0, < 3.0.0) + colored + commander-fastlane (>= 4.4.6, < 5.0.0) + dotenv (>= 2.1.1, < 3.0.0) + emoji_regex (>= 0.1, < 4.0) + excon (>= 0.71.0, < 1.0.0) + faraday (~> 1.0) + faraday-cookie_jar (~> 0.0.6) + faraday_middleware (~> 1.0) + fastimage (>= 2.1.0, < 3.0.0) + gh_inspector (>= 1.1.2, < 2.0.0) + google-api-client (>= 0.37.0, < 0.39.0) + google-cloud-storage (>= 1.15.0, < 2.0.0) + highline (>= 1.7.2, < 2.0.0) + json (< 3.0.0) + jwt (>= 2.1.0, < 3) + mini_magick (>= 4.9.4, < 5.0.0) + multipart-post (~> 2.0.0) + plist (>= 3.1.0, < 4.0.0) + rubyzip (>= 2.0.0, < 3.0.0) + security (= 0.1.3) + simctl (~> 1.6.3) + slack-notifier (>= 2.0.0, < 3.0.0) + terminal-notifier (>= 2.0.0, < 3.0.0) + terminal-table (>= 1.4.5, < 2.0.0) + tty-screen (>= 0.6.3, < 1.0.0) + tty-spinner (>= 0.8.0, < 1.0.0) + word_wrap (~> 1.0.0) + xcodeproj (>= 1.13.0, < 2.0.0) + xcpretty (~> 0.3.0) + xcpretty-travis-formatter (>= 0.0.3) + gh_inspector (1.1.3) + google-api-client (0.38.0) + addressable (~> 2.5, >= 2.5.1) + googleauth (~> 0.9) + httpclient (>= 2.8.1, < 3.0) + mini_mime (~> 1.0) + representable (~> 3.0) + retriable (>= 2.0, < 4.0) + signet (~> 0.12) + google-cloud-core (1.5.0) + google-cloud-env (~> 1.0) + google-cloud-errors (~> 1.0) + google-cloud-env (1.3.3) + faraday (>= 0.17.3, < 2.0) + google-cloud-errors (1.0.1) + google-cloud-storage (1.27.0) + addressable (~> 2.5) + digest-crc (~> 0.4) + google-api-client (~> 0.33) + google-cloud-core (~> 1.2) + googleauth (~> 0.9) + mini_mime (~> 1.0) + googleauth (0.13.1) + faraday (>= 0.17.3, < 2.0) + jwt (>= 1.4, < 3.0) + memoist (~> 0.16) + multi_json (~> 1.11) + os (>= 0.9, < 2.0) + signet (~> 0.14) + highline (1.7.10) + http-cookie (1.0.3) + domain_name (~> 0.5) + httpclient (2.8.3) + jmespath (1.4.0) + json (2.3.1) + jwt (2.2.1) + memoist (0.16.2) + mini_magick (4.10.1) + mini_mime (1.0.2) + multi_json (1.15.0) + multipart-post (2.0.0) + nanaimo (0.3.0) + naturally (2.2.0) + os (1.1.1) + plist (3.5.0) + public_suffix (4.0.5) + rake (13.0.1) + representable (3.0.4) + declarative (< 0.1.0) + declarative-option (< 0.2.0) + uber (< 0.2.0) + retriable (3.1.2) + rouge (2.0.7) + rubyzip (2.3.0) + security (0.1.3) + signet (0.14.0) + addressable (~> 2.3) + faraday (>= 0.17.3, < 2.0) + jwt (>= 1.5, < 3.0) + multi_json (~> 1.10) + simctl (1.6.8) + CFPropertyList + naturally + slack-notifier (2.3.2) + terminal-notifier (2.0.0) + terminal-table (1.8.0) + unicode-display_width (~> 1.1, >= 1.1.1) + tty-cursor (0.7.1) + tty-screen (0.8.1) + tty-spinner (0.9.3) + tty-cursor (~> 0.7) + uber (0.1.0) + unf (0.1.4) + unf_ext + unf_ext (0.0.7.7) + unicode-display_width (1.7.0) + word_wrap (1.0.0) + xcodeproj (1.17.1) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.3.0) + xcpretty (0.3.0) + rouge (~> 2.0.7) + xcpretty-travis-formatter (1.0.0) + xcpretty (~> 0.2, >= 0.0.7) + +PLATFORMS + ruby + +DEPENDENCIES + fastlane + +BUNDLED WITH + 2.1.4 diff --git a/README.md b/README.md index 9babb0d..f401516 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@

- + @@ -12,8 +12,9 @@

## Screenshots -[](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_01.png) -[](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_02.png) +[](fastlane/metadata/android/en-US/images/phoneScreenshots/1_en-US.png) +[](fastlane/metadata/android/en-US/images/phoneScreenshots/2_en-US.png) +[](fastlane/metadata/android/en-US/images/phoneScreenshots/3_en-US.png) ## Description PeerTube is a federated video streaming platform that is community-owned and ad-free, with no vendor lock-in. This client allows you to watch and browse videos on a server of your choice in the PeerTube network. @@ -27,6 +28,13 @@ Please note this is app is in beta and is still missing a lot of features. * Beta Test on Google Play: https://play.google.com/store/apps/details?id=net.schueller.peertube * F-Droid: https://f-droid.org/packages/net.schueller.peertube/ +## Releases +Release Tags are automatically built and deployed to the play store but not released to production right away. +To use the latest tagged release download it from github or fdroid (~1 day delay). + +## Reproducible Builds +Reproducible builds currently does not work. + ## Help Translate * https://hosted.weblate.org/projects/peertube/ @@ -47,11 +55,11 @@ Please note this is app is in beta and is still missing a lot of features. * Video speed selection * Video quality selection * Server selection +* Video overlay play and draggable video window ## Coming soon * Video Playback via WebRTC -* Video overlay play and draggable video window * Comment videos * Report Videos * User / Channel Overview Page @@ -65,4 +73,4 @@ Whether you have ideas, translations, design changes, code cleaning, or real hea -Bitcoin: 1LoTXo728HzYTtyfbkaf5ewSRvu8ABTDPm +Bitcoin: 1LoTXo728HzYTtyfbkaf5ewSRvu8ABTDPm diff --git a/REPRODUCIBLE_BUILDS.md b/REPRODUCIBLE_BUILDS.md new file mode 100644 index 0000000..7be7bdf --- /dev/null +++ b/REPRODUCIBLE_BUILDS.md @@ -0,0 +1,62 @@ +# Reproducible Builds + +Note: This does not work at this time + +## Install Docker + +Download and install [Docker](https://www.docker.com/). + +## Check your Thorium app version and build timestamp + +1. Open the Thorium app +2. Go to Settings +3. Check the app version listed under About 'Version' (e.g., 1.0.44), and record its value to be used later +4. Check the build timestamp under About 'Build Time' (e.g., 1593942384524), and record its value to be used later + +## Download the App open-source code + +1. Make sure you have `git` installed +2. Clone the Github repository +3. Checkout the Tag that corresponds to the version of your Thorium app (e.g., 1.0.44) + +```shell +git clone https://github.com/sschueller/peertube-android ~/peertube-android +cd ~/peertube-android +git checkout v1.0.44 +``` + +## Build the project using Docker + +1. Build a Docker Image with the required Android Tools +2. Build the App in the Docker Container while specifying the build timestamp that was recorded earlier (e.g., 1593942384524) +3. Copy the freshly-built APK + +```shell +cd ~/peertube-android +docker build -t thorium-builder . +docker run --rm -v ~/Private/peertube:/home/peertube -w /home/peertube thorium-builder gradle assembleRelease -PkeystorePassword=securePassword -PkeyAliasPassword=securePassword -PkeystoreFile=build.keystore -PbuildTimestamp=1593973044091 +cp app/build/outputs/apk/release/app-release-unsigned.apk thorium-built.apk +``` + +## Extract the Play Store APK from your phone + +1. Make sure you have `adb` installed +2. Connect your phone to your computer +3. Extract the APK from the phone + +```shell +cd ~/peertube-android +adb shell pm path net.schueller.peertube +adb pull /data/app/net.schueller.peertube-mCeISw_AujlMBHyPfVhdSg==/base.apk thorium-store.apk +``` + +## Compare the two files + +1. Make sure you have `python` installed +2. Use the `apkdiff` script to compare the APKs + +```shell +cd ~/peertube-android +./apkdiff.py thorium-built.apk thorium-store.apk +``` + diff --git a/apkdiff.py b/apkdiff.py new file mode 100755 index 0000000..13df537 --- /dev/null +++ b/apkdiff.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python +# Taken from https://github.com/DrKLO/Telegram/blob/master/apkdiff.py on June 4th, 2020 + +import sys +from zipfile import ZipFile + +def compareFiles(first, second): + while True: + firstBytes = first.read(4096); + secondBytes = second.read(4096); + if firstBytes != secondBytes: + return False + + if firstBytes == b"": + break + + return True + +def compare(first, second): + FILES_TO_IGNORE = ["META-INF/MANIFEST.MF", "META-INF/CERT.RSA", "META-INF/CERT.SF"] + + firstZip = ZipFile(first, 'r') + secondZip = ZipFile(second, 'r') + + firstList = list(filter(lambda firstInfo: firstInfo.filename not in FILES_TO_IGNORE, firstZip.infolist())) + secondList = list(filter(lambda secondInfo: secondInfo.filename not in FILES_TO_IGNORE, secondZip.infolist())) + + if len(firstList) != len(secondList): + print("APKs has different amount of files (%d != %d)" % (len(firstList), len(secondList))) + return False + + for firstInfo in firstList: + found = False + for secondInfo in secondList: + if firstInfo.filename == secondInfo.filename: + found = True + firstFile = firstZip.open(firstInfo, 'r') + secondFile = secondZip.open(secondInfo, 'r') + + if compareFiles(firstFile, secondFile) != True: + print("APK file %s does not match" % firstInfo.filename) + return False + + secondList.remove(secondInfo) + break + + if found == False: + print("file %s not found in second APK" % firstInfo.filename) + return False + + if len(secondList) != 0: + for secondInfo in secondList: + print("file %s not found in first APK" % secondInfo.filename) + return False + + return True + +if __name__ == '__main__': + if len(sys.argv) != 3: + print("Usage: apkdiff ") + sys.exit(1) + + if sys.argv[1] == sys.argv[2] or compare(sys.argv[1], sys.argv[2]) == True: + print("APKs are the same!") + else: + print("APKs are different!") \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index dd038df..ef4901c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,19 +1,54 @@ -apply plugin: 'com.android.application' +plugins { + id 'com.android.application' + id 'kotlin-android' + id 'kotlin-parcelize' + id 'kotlin-kapt' +} + +ext.readProperty = { paramName -> readPropertyWithDefault(paramName, null) } +ext.readPropertyWithDefault = { paramName, defaultValue -> + if (project.hasProperty(paramName)) { + return project.getProperties().get(paramName) + } else { + Properties properties = new Properties() + if (project.rootProject.file('local.properties').exists()) { + properties.load(project.rootProject.file('local.properties').newDataInputStream()) + } + if (properties.getProperty(paramName) != null) { + return properties.getProperty(paramName) + } else { + return defaultValue + } + } +} + +// Try reading secrets from file +def secretsPropertiesFile = rootProject.file("secrets.properties") +def secretProperties = new Properties() + +if (secretsPropertiesFile.exists()) { + secretProperties.load(new FileInputStream(secretsPropertiesFile)) +} +// Otherwise read from environment variables, this happens in CI +else { + secretProperties.setProperty("signing_keystore_password", "${System.getenv('signing_keystore_password')}") + secretProperties.setProperty("signing_key_password", "${System.getenv('signing_key_password')}") + secretProperties.setProperty("signing_key_alias", "${System.getenv('signing_key_alias')}") +} android { compileSdkVersion 29 + buildToolsVersion "29.0.3" + defaultConfig { applicationId "net.schueller.peertube" minSdkVersion 21 targetSdkVersion 29 - versionCode 1041 - versionName "1.0.41" + versionCode Integer.valueOf(System.getenv("VERSION_CODE") ?: 1) + versionName System.getenv("VERSION_NAME") + "-" + System.getenv("VERSION_SHA") + buildConfigField "long", "BUILD_TIME", readPropertyWithDefault('buildTimestamp', System.currentTimeMillis()) + 'L' testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - ext { - libVersions = [ - exoplayer: '2.11.6' - ] - } + javaCompileOptions { annotationProcessorOptions { arguments = [ @@ -22,56 +57,24 @@ android { "room.expandProjection": "true"] } } - dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - - // Layouts and design - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - implementation 'androidx.appcompat:appcompat:1.1.0' - implementation 'androidx.cardview:cardview:1.0.0' - implementation 'androidx.recyclerview:recyclerview:1.1.0' - implementation 'androidx.legacy:legacy-support-v13:1.0.0' - implementation 'com.google.android.material:material:1.1.0' - implementation 'de.hdodenhof:circleimageview:3.0.0' - - // font awesome - implementation "com.mikepenz:iconics-core:3.1.0" - implementation 'com.mikepenz:fontawesome-typeface:5.3.1.1@aar' - - // http client / REST - implementation 'com.squareup.okhttp3:okhttp:4.3.1' - implementation 'com.squareup.retrofit2:retrofit:2.5.0' - - // image downloading and caching library - implementation 'com.squareup.picasso:picasso:2.71828' - - // json decoder/encoder - implementation 'com.google.code.gson:gson:2.8.6' - implementation 'com.squareup.retrofit2:converter-gson:2.5.0' - - // Torrents and WebRTC - implementation 'com.github.TorrentStream:TorrentStream-Android:2.6.1' -// implementation "com.github.TorrentStream:TorrentStreamServer-Android:1.0.1" -// implementation 'org.webrtc:google-webrtc:1.0.+' - - // video player repo:jcenter() - implementation "com.google.android.exoplayer:exoplayer-core:$libVersions.exoplayer" - implementation "com.google.android.exoplayer:exoplayer-dash:$libVersions.exoplayer" - implementation "com.google.android.exoplayer:exoplayer-ui:$libVersions.exoplayer" - implementation "com.google.android.exoplayer:exoplayer-hls:$libVersions.exoplayer" - implementation "com.google.android.exoplayer:exoplayer-smoothstreaming:$libVersions.exoplayer" - implementation "com.google.android.exoplayer:extension-mediasession:$libVersions.exoplayer" - - // testing - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.2.0' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + } + signingConfigs { + release { + // You need to specify either an absolute path or include the + // keystore file in the same directory as the build.gradle file. + storeFile file("../android-signing-keystore.jks") + storePassword "${secretProperties['signing_keystore_password']}" + keyAlias "${secretProperties['signing_key_alias']}" + keyPassword "${secretProperties['signing_key_password']}" } } + buildTypes { release { minifyEnabled false + testCoverageEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.release } } compileOptions { @@ -82,28 +85,91 @@ android { applicationVariants.all { variant -> variant.resValue "string", "versionName", variant.versionName } + + buildFeatures{ + viewBinding = true + } + } +def room_version = "2.2.6" +def lifecycleVersion = '2.2.0' +def exoplayer = '2.12.3' +def fragment_version = "1.2.5" + dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) - def room_version = "2.2.5" - def archLifecycleVersion = '2.1.0' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta7' - implementation 'androidx.appcompat:appcompat:1.1.0' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - implementation 'com.google.android.material:material:1.1.0' + // Layouts and design + implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'com.google.android.material:material:1.2.1' + implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" + implementation "androidx.fragment:fragment-ktx:$fragment_version" + + implementation 'de.hdodenhof:circleimageview:3.0.0' + + // font awesome + implementation "com.mikepenz:iconics-core:3.1.0" + implementation 'com.mikepenz:fontawesome-typeface:5.3.1.1@aar' + + // http client / REST + implementation 'com.squareup.okhttp3:okhttp:4.9.0' + implementation 'com.squareup.retrofit2:retrofit:2.9.0' + + // image downloading and caching library + implementation 'com.squareup.picasso:picasso:2.71828' + + // json decoder/encoder + implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.squareup.retrofit2:converter-gson:2.9.0' + + // Torrents and WebRTC + implementation 'com.github.TorrentStream:TorrentStream-Android:2.7.0' +// implementation "com.github.TorrentStream:TorrentStreamServer-Android:1.0.1" +// implementation 'org.webrtc:google-webrtc:1.0.+' + + // video player repo:jcenter() + implementation "com.google.android.exoplayer:exoplayer-core:$exoplayer" + implementation "com.google.android.exoplayer:exoplayer-dash:$exoplayer" + implementation "com.google.android.exoplayer:exoplayer-ui:$exoplayer" + implementation "com.google.android.exoplayer:exoplayer-hls:$exoplayer" + implementation "com.google.android.exoplayer:exoplayer-smoothstreaming:$exoplayer" + implementation "com.google.android.exoplayer:extension-mediasession:$exoplayer" + implementation "com.google.android.exoplayer:extension-okhttp:$exoplayer" + + // date formatter + implementation 'org.ocpsoft.prettytime:prettytime:4.0.4.Final' + + // Version comparison + implementation 'org.apache.maven:maven-artifact:3.5.0' // database lib implementation "androidx.room:room-runtime:$room_version" - implementation 'androidx.legacy:legacy-support-v4:1.0.0' - implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' - annotationProcessor "androidx.room:room-compiler:$room_version" - androidTestImplementation "androidx.room:room-testing:$room_version" + implementation "androidx.room:room-ktx:$room_version" + kapt "androidx.room:room-compiler:$room_version" // Lifecycle components - implementation "androidx.lifecycle:lifecycle-extensions:$archLifecycleVersion" - annotationProcessor "androidx.lifecycle:lifecycle-common-java8:$archLifecycleVersion" + implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion" + kapt "androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion" + implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion" - implementation 'androidx.preference:preference:1.1.1' + + implementation 'androidx.preference:preference-ktx:1.1.1' + + // testing + testImplementation 'junit:junit:4.13' + androidTestImplementation 'androidx.test:runner:1.3.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + androidTestImplementation "androidx.room:room-testing:$room_version" } + +tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { + kotlinOptions { + jvmTarget = "1.8" + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ee09a9b..3091705 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -49,7 +49,7 @@ android:label="@string/title_activity_settings" android:theme="@style/AppTheme.NoActionBar" /> + * Copyright (C) 2020 Stefan Schüller * - * License: GPL-3.0+ * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ package net.schueller.peertube.activity; @@ -37,6 +36,7 @@ import net.schueller.peertube.R; import net.schueller.peertube.adapter.ChannelAdapter; import net.schueller.peertube.adapter.VideoAdapter; import net.schueller.peertube.helper.APIUrlHelper; +import net.schueller.peertube.helper.ErrorHelper; import net.schueller.peertube.helper.MetaDataHelper; import net.schueller.peertube.model.Account; import net.schueller.peertube.model.Avatar; @@ -96,7 +96,7 @@ public class AccountActivity extends CommonActivity { apiBaseURL = APIUrlHelper.getUrlWithVersion(this); - userService = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(GetUserService.class); + userService = RetrofitInstance.getRetrofitInstance(apiBaseURL, APIUrlHelper.useInsecureConnection(this)).create(GetUserService.class); recyclerViewVideos = findViewById(R.id.account_video_recyclerView); recyclerViewChannels = findViewById(R.id.account_channel_recyclerView); @@ -206,7 +206,7 @@ public class AccountActivity extends CommonActivity { } } else { - Toast.makeText(AccountActivity.this, getString(R.string.api_error), Toast.LENGTH_SHORT).show(); + ErrorHelper.showToastFromCommunicationError( AccountActivity.this, null ); } @@ -215,7 +215,7 @@ public class AccountActivity extends CommonActivity { @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) { Log.wtf(TAG, t.fillInStackTrace()); - Toast.makeText(AccountActivity.this, getString(R.string.api_error), Toast.LENGTH_SHORT).show(); + ErrorHelper.showToastFromCommunicationError( AccountActivity.this, t ); } }); @@ -226,7 +226,7 @@ public class AccountActivity extends CommonActivity { isLoadingVideos = false; - GetVideoDataService service = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(GetVideoDataService.class); + GetVideoDataService service = RetrofitInstance.getRetrofitInstance(apiBaseURL, APIUrlHelper.useInsecureConnection(this)).create(GetVideoDataService.class); Call call; call = service.getAccountVideosData(displayNameAndHost, videosStart, videosCount, videosSort); @@ -247,8 +247,7 @@ public class AccountActivity extends CommonActivity { } } else{ - Toast.makeText(AccountActivity.this, getString(R.string.api_error), Toast.LENGTH_SHORT).show(); - + ErrorHelper.showToastFromCommunicationError( AccountActivity.this, null ); } isLoadingVideos = false; @@ -258,7 +257,7 @@ public class AccountActivity extends CommonActivity { @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) { Log.wtf("err", t.fillInStackTrace()); - Toast.makeText(AccountActivity.this, getString(R.string.api_error), Toast.LENGTH_SHORT).show(); + ErrorHelper.showToastFromCommunicationError( AccountActivity.this, t ); isLoadingVideos = false; swipeRefreshLayoutVideos.setRefreshing(false); } @@ -281,7 +280,7 @@ public class AccountActivity extends CommonActivity { } else { - Toast.makeText(AccountActivity.this, getString(R.string.api_error), Toast.LENGTH_SHORT).show(); + ErrorHelper.showToastFromCommunicationError( AccountActivity.this, null ); } @@ -290,7 +289,7 @@ public class AccountActivity extends CommonActivity { @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) { Log.wtf(TAG, t.fillInStackTrace()); - Toast.makeText(AccountActivity.this, getString(R.string.api_error), Toast.LENGTH_SHORT).show(); + ErrorHelper.showToastFromCommunicationError( AccountActivity.this, t ); } }); } diff --git a/app/src/main/java/net/schueller/peertube/activity/AppCompatPreferenceActivity.java b/app/src/main/java/net/schueller/peertube/activity/AppCompatPreferenceActivity.java deleted file mode 100644 index 36d5fe0..0000000 --- a/app/src/main/java/net/schueller/peertube/activity/AppCompatPreferenceActivity.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2018 Stefan Schüller - * - * License: GPL-3.0+ - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package net.schueller.peertube.activity; - -import android.content.SharedPreferences; -import android.content.res.Configuration; -import android.os.Bundle; -import android.preference.PreferenceActivity; -import androidx.annotation.LayoutRes; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatDelegate; - -import android.preference.PreferenceManager; -import android.view.MenuInflater; -import android.view.View; -import android.view.ViewGroup; - -import static net.schueller.peertube.helper.Constants.DEFAULT_THEME; -import static net.schueller.peertube.helper.Constants.THEME_PREF_KEY; - -/** - * A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls - * to be used with AppCompat. - */ -public abstract class AppCompatPreferenceActivity extends PreferenceActivity { - - private AppCompatDelegate mDelegate; - - @Override - protected void onCreate(Bundle savedInstanceState) { - getDelegate().installViewFactory(); - getDelegate().onCreate(savedInstanceState); - super.onCreate(savedInstanceState); - - // TODO: cleanup this duplication - - // Set Night Mode - SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); - AppCompatDelegate.setDefaultNightMode(sharedPref.getBoolean("pref_dark_mode", false) ? - AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO); - - // Set theme - setTheme(getResources().getIdentifier( - sharedPref.getString(THEME_PREF_KEY, DEFAULT_THEME), - "style", - getPackageName()) - ); - } - - @Override - protected void onPostCreate(Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - getDelegate().onPostCreate(savedInstanceState); - } - - public ActionBar getSupportActionBar() { - return getDelegate().getSupportActionBar(); - } - -// public void setSupportActionBar(@Nullable Toolbar toolbar) { -// getDelegate().setSupportActionBar(toolbar); -// } - - @Override - public MenuInflater getMenuInflater() { - return getDelegate().getMenuInflater(); - } - - @Override - public void setContentView(@LayoutRes int layoutResID) { - getDelegate().setContentView(layoutResID); - } - - @Override - public void setContentView(View view) { - getDelegate().setContentView(view); - } - - @Override - public void setContentView(View view, ViewGroup.LayoutParams params) { - getDelegate().setContentView(view, params); - } - - @Override - public void addContentView(View view, ViewGroup.LayoutParams params) { - getDelegate().addContentView(view, params); - } - - @Override - protected void onPostResume() { - super.onPostResume(); - getDelegate().onPostResume(); - } - - @Override - protected void onTitleChanged(CharSequence title, int color) { - super.onTitleChanged(title, color); - getDelegate().setTitle(title); - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - getDelegate().onConfigurationChanged(newConfig); - } - - @Override - protected void onStop() { - super.onStop(); - getDelegate().onStop(); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - getDelegate().onDestroy(); - } - - public void invalidateOptionsMenu() { - getDelegate().invalidateOptionsMenu(); - } - - private AppCompatDelegate getDelegate() { - if (mDelegate == null) { - mDelegate = AppCompatDelegate.create(this, null); - } - return mDelegate; - } -} diff --git a/app/src/main/java/net/schueller/peertube/activity/CommonActivity.java b/app/src/main/java/net/schueller/peertube/activity/CommonActivity.java index a733fca..d68ffe4 100644 --- a/app/src/main/java/net/schueller/peertube/activity/CommonActivity.java +++ b/app/src/main/java/net/schueller/peertube/activity/CommonActivity.java @@ -1,35 +1,34 @@ /* - * Copyright 2018 Stefan Schüller + * Copyright (C) 2020 Stefan Schüller * - * License: GPL-3.0+ * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ package net.schueller.peertube.activity; import android.content.SharedPreferences; import android.content.res.Configuration; +import android.content.res.Resources; import android.os.Bundle; import android.preference.PreferenceManager; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.app.AppCompatDelegate; +import net.schueller.peertube.R; import java.util.Locale; -import static net.schueller.peertube.helper.Constants.DEFAULT_THEME; -import static net.schueller.peertube.helper.Constants.THEME_PREF_KEY; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatDelegate; public class CommonActivity extends AppCompatActivity { @@ -39,30 +38,45 @@ public class CommonActivity extends AppCompatActivity { // Set Night Mode SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); - AppCompatDelegate.setDefaultNightMode(sharedPref.getBoolean("pref_dark_mode", false) ? + AppCompatDelegate.setDefaultNightMode(sharedPref.getBoolean(getString(R.string.pref_dark_mode_key), false) ? AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO); // Set theme setTheme(getResources().getIdentifier( - sharedPref.getString(THEME_PREF_KEY, DEFAULT_THEME), + sharedPref.getString( + getString(R.string.pref_theme_key), + getString(R.string.app_default_theme) + ), "style", getPackageName()) ); // Set language - String countryCode=sharedPref.getString("pref_language_app","en"); - Locale locale=new Locale(countryCode);; + String countryCode = sharedPref.getString(getString(R.string.pref_language_app_key), null); + + if (countryCode == null) { + return; + } + + setLocale(countryCode); + } + + + public void setLocale(String languageCode) { + + Locale locale = new Locale(languageCode); + //Neither Chinese language choice was working, found this fix on stack overflow - if(countryCode.equals("zh-rCN")) + if (languageCode.equals("zh-rCN")) locale = Locale.SIMPLIFIED_CHINESE; - if(countryCode.equals("zh-rTW")) + if (languageCode.equals("zh-rTW")) locale = Locale.TRADITIONAL_CHINESE; Locale.setDefault(locale); - Configuration config = getBaseContext().getResources().getConfiguration(); - config.locale = locale; - getBaseContext().getResources().updateConfiguration(config, - getBaseContext().getResources().getDisplayMetrics()); - } + Resources resources = getResources(); + Configuration config = resources.getConfiguration(); + config.setLocale(locale); + resources.updateConfiguration(config, resources.getDisplayMetrics()); + } } diff --git a/app/src/main/java/net/schueller/peertube/activity/MeActivity.java b/app/src/main/java/net/schueller/peertube/activity/MeActivity.java index 9e0c6da..36388af 100644 --- a/app/src/main/java/net/schueller/peertube/activity/MeActivity.java +++ b/app/src/main/java/net/schueller/peertube/activity/MeActivity.java @@ -1,19 +1,18 @@ /* - * Copyright 2018 Stefan Schüller + * Copyright (C) 2020 Stefan Schüller * - * License: GPL-3.0+ * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ package net.schueller.peertube.activity; @@ -31,6 +30,7 @@ import android.widget.TextView; import net.schueller.peertube.R; import net.schueller.peertube.helper.APIUrlHelper; +import net.schueller.peertube.helper.ErrorHelper; import net.schueller.peertube.model.Avatar; import net.schueller.peertube.model.Me; import net.schueller.peertube.network.GetUserService; @@ -118,7 +118,7 @@ public class MeActivity extends CommonActivity { String apiBaseURL = APIUrlHelper.getUrlWithVersion(this); String baseURL = APIUrlHelper.getUrl(this); - GetUserService service = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(GetUserService.class); + GetUserService service = RetrofitInstance.getRetrofitInstance(apiBaseURL, APIUrlHelper.useInsecureConnection(this)).create(GetUserService.class); Call call = service.getMe(); @@ -162,6 +162,7 @@ public class MeActivity extends CommonActivity { @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) { + ErrorHelper.showToastFromCommunicationError( MeActivity.this, t ); account.setVisibility(View.GONE); } }); diff --git a/app/src/main/java/net/schueller/peertube/activity/SelectServerActivity.java b/app/src/main/java/net/schueller/peertube/activity/SearchServerActivity.java similarity index 66% rename from app/src/main/java/net/schueller/peertube/activity/SelectServerActivity.java rename to app/src/main/java/net/schueller/peertube/activity/SearchServerActivity.java index a4c6186..9d9463a 100644 --- a/app/src/main/java/net/schueller/peertube/activity/SelectServerActivity.java +++ b/app/src/main/java/net/schueller/peertube/activity/SearchServerActivity.java @@ -1,24 +1,22 @@ /* - * Copyright 2018 Stefan Schüller + * Copyright (C) 2020 Stefan Schüller * - * License: GPL-3.0+ * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ package net.schueller.peertube.activity; import androidx.annotation.NonNull; -import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -27,40 +25,37 @@ import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; -import android.content.Intent; -import android.content.SharedPreferences; import android.os.Bundle; -import android.preference.PreferenceManager; import android.util.Log; -import android.util.Patterns; +import android.view.KeyEvent; import android.view.View; -import android.widget.Button; +import android.view.inputmethod.EditorInfo; +import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import net.schueller.peertube.R; -import net.schueller.peertube.adapter.ServerAdapter; -import net.schueller.peertube.adapter.VideoAdapter; +import net.schueller.peertube.adapter.ServerSearchAdapter; import net.schueller.peertube.helper.APIUrlHelper; +import net.schueller.peertube.helper.ErrorHelper; import net.schueller.peertube.model.ServerList; -import net.schueller.peertube.model.VideoList; import net.schueller.peertube.network.GetServerListDataService; -import net.schueller.peertube.network.GetVideoDataService; import net.schueller.peertube.network.RetrofitInstance; import java.util.ArrayList; import java.util.Objects; -import static net.schueller.peertube.helper.Constants.DEFAULT_THEME; -import static net.schueller.peertube.helper.Constants.THEME_PREF_KEY; +public class SearchServerActivity extends CommonActivity { -public class SelectServerActivity extends CommonActivity { - - private ServerAdapter serverAdapter; + private ServerSearchAdapter serverAdapter; private SwipeRefreshLayout swipeRefreshLayout; + private EditText searchTextView; + + private final static String TAG = "SearchServerActivity"; private int currentStart = 0; - private int count = 12; + private final int count = 12; + private String lastSearchtext = ""; private TextView emptyView; private RecyclerView recyclerView; @@ -76,7 +71,7 @@ public class SelectServerActivity extends CommonActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_server_selection); + setContentView(R.layout.activity_search_server); // Attaching the layout to the toolbar object Toolbar toolbar = findViewById(R.id.tool_bar_server_selection); @@ -89,21 +84,30 @@ public class SelectServerActivity extends CommonActivity { } + TextView.OnEditorActionListener onSearchTextValidated = ( textView, i, keyEvent ) -> { + if ( keyEvent != null && keyEvent.getKeyCode() == KeyEvent.KEYCODE_ENTER + || i == EditorInfo.IME_ACTION_GO ) { + loadServers(currentStart, count, textView.getText().toString()); + } + return false; + }; private void loadList() { recyclerView = findViewById(R.id.serverRecyclerView); swipeRefreshLayout = findViewById(R.id.serversSwipeRefreshLayout); + searchTextView = findViewById(R.id.search_server_input_field ); + searchTextView.setOnEditorActionListener( onSearchTextValidated ); emptyView = findViewById(R.id.empty_server_selection_view); - RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(SelectServerActivity.this); + RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(SearchServerActivity.this); recyclerView.setLayoutManager(layoutManager); - serverAdapter = new ServerAdapter(new ArrayList<>(), this); + serverAdapter = new ServerSearchAdapter(new ArrayList<>(), this); recyclerView.setAdapter(serverAdapter); - loadServers(currentStart, count); + loadServers(currentStart, count, searchTextView.getText().toString() ); recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override @@ -119,7 +123,7 @@ public class SelectServerActivity extends CommonActivity { if (!recyclerView.canScrollVertically(RecyclerView.FOCUS_DOWN)) { if (!isLoading) { currentStart = currentStart + count; - loadServers(currentStart, count); + loadServers(currentStart, count, searchTextView.getText().toString()); } } } @@ -131,26 +135,29 @@ public class SelectServerActivity extends CommonActivity { // Refresh items if (!isLoading) { currentStart = 0; - loadServers(currentStart, count); + loadServers(currentStart, count, searchTextView.getText().toString()); } }); } - - - private void loadServers(int start, int count) { + private void loadServers(int start, int count, String searchtext) { isLoading = true; GetServerListDataService service = RetrofitInstance.getRetrofitInstance( - APIUrlHelper.getServerIndexUrl(SelectServerActivity.this) - ).create(GetServerListDataService.class); + APIUrlHelper.getServerIndexUrl(SearchServerActivity.this) + , APIUrlHelper.useInsecureConnection(this)).create(GetServerListDataService.class); + if ( !searchtext.equals( lastSearchtext ) ) + { + currentStart = 0; + lastSearchtext = searchtext; + } Call call; - call = service.getInstancesData(start, count); + call = service.getInstancesData(start, count, searchtext); Log.d("URL Called", call.request().url() + ""); @@ -183,7 +190,7 @@ public class SelectServerActivity extends CommonActivity { @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) { Log.wtf("err", t.fillInStackTrace()); - Toast.makeText(SelectServerActivity.this, getString(R.string.api_error), Toast.LENGTH_SHORT).show(); + ErrorHelper.showToastFromCommunicationError( SearchServerActivity.this, t ); isLoading = false; swipeRefreshLayout.setRefreshing(false); } diff --git a/app/src/main/java/net/schueller/peertube/activity/ServerAddressBookActivity.java b/app/src/main/java/net/schueller/peertube/activity/ServerAddressBookActivity.java deleted file mode 100644 index a398b64..0000000 --- a/app/src/main/java/net/schueller/peertube/activity/ServerAddressBookActivity.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright 2018 Stefan Schüller - * - * License: GPL-3.0+ - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package net.schueller.peertube.activity; - -import android.app.AlertDialog; -import android.net.Uri; -import android.os.Bundle; -import android.util.Log; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.View; -import android.widget.EditText; - -import com.google.android.material.floatingactionbutton.FloatingActionButton; - -import androidx.annotation.NonNull; - -import androidx.appcompat.widget.Toolbar; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentTransaction; -import androidx.lifecycle.ViewModelProvider; -import androidx.recyclerview.widget.ItemTouchHelper; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import net.schueller.peertube.R; -import net.schueller.peertube.adapter.ServerListAdapter; -import net.schueller.peertube.database.Server; -import net.schueller.peertube.database.ServerViewModel; -import net.schueller.peertube.fragment.AddServerFragment; - - -import java.util.Objects; - -public class ServerAddressBookActivity extends CommonActivity implements AddServerFragment.OnFragmentInteractionListener { - - private String TAG = "ServerAddressBookActivity"; - public static final String EXTRA_REPLY = "net.schueller.peertube.room.REPLY"; - - private ServerViewModel mServerViewModel; - private AddServerFragment addServerFragment; - private FloatingActionButton floatingActionButton; - private FragmentManager fragmentManager; - - @Override - public boolean onSupportNavigateUp() { - finish(); // close this activity as oppose to navigating up - return false; - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_server_address_book); - - // Attaching the layout to the toolbar object - Toolbar toolbar = findViewById(R.id.tool_bar_server_address_book); - // Setting toolbar as the ActionBar with setSupportActionBar() call - setSupportActionBar(toolbar); - Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true); - getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_baseline_close_24); - - mServerViewModel = new ViewModelProvider(this).get(ServerViewModel.class); - - showServers(); - - floatingActionButton = findViewById(R.id.add_server); - floatingActionButton.setOnClickListener(view -> { - - Log.d(TAG, "Click"); - - fragmentManager = getSupportFragmentManager(); - FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); - - addServerFragment = new AddServerFragment(); - fragmentTransaction.replace(R.id.server_book, addServerFragment); - fragmentTransaction.commit(); - - floatingActionButton.hide(); - - }); - - } - - @Override - public void onFragmentInteraction(Uri uri) { - - } - - @Override - public void onPointerCaptureChanged(boolean hasCapture) { - - } - - - public void showServers() - { - RecyclerView recyclerView = findViewById(R.id.server_list_recyclerview); - final ServerListAdapter adapter = new ServerListAdapter(this); - recyclerView.setAdapter(adapter); - recyclerView.setLayoutManager(new LinearLayoutManager(this)); - - // Delete items on swipe - ItemTouchHelper helper = new ItemTouchHelper( - new ItemTouchHelper.SimpleCallback(0, - ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) { - @Override - public boolean onMove(@NonNull RecyclerView recyclerView, - @NonNull RecyclerView.ViewHolder viewHolder, - @NonNull RecyclerView.ViewHolder target) { - return false; - } - - @Override - public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, - int direction) { - - - new AlertDialog.Builder(ServerAddressBookActivity.this) - .setTitle(getString(R.string.server_book_del_alert_title)) - .setMessage(getString(R.string.server_book_del_alert_msg)) - .setPositiveButton(android.R.string.yes, (dialog, which) -> { - int position = viewHolder.getAdapterPosition(); - Server server = adapter.getServerAtPosition(position); -// Toast.makeText(ServerAddressBookActivity.this, "Deleting " + -// server.getServerName(), Toast.LENGTH_LONG).show(); - // Delete the server - mServerViewModel.delete(server); - }) - .setNegativeButton(android.R.string.no, (dialog, which) -> { - adapter.notifyItemChanged(viewHolder.getAdapterPosition()); - }) - .setIcon(android.R.drawable.ic_dialog_alert) - .show(); - - } - }); - helper.attachToRecyclerView(recyclerView); - - - // Update the cached copy of the words in the adapter. - mServerViewModel.getAllServers().observe(this, adapter::setServers); - - } - - public void addServer(View view) - { - Log.d(TAG, "addServer"); - - EditText serverLabel = view.findViewById(R.id.serverLabel); - EditText serverUrl = view.findViewById(R.id.serverUrl); - EditText serverUsername = view.findViewById(R.id.serverUsername); - EditText serverPassword = view.findViewById(R.id.serverPassword); - - Server server = new Server(serverLabel.getText().toString()); - - server.setServerHost(serverUrl.getText().toString()); - server.setUsername(serverUsername.getText().toString()); - server.setPassword(serverPassword.getText().toString()); - - mServerViewModel.insert(server); - - FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); - fragmentTransaction.remove(addServerFragment); - fragmentTransaction.commit(); - - floatingActionButton.show(); - - } - - public void testServer() - { - - } - -} diff --git a/app/src/main/java/net/schueller/peertube/activity/ServerAddressBookActivity.kt b/app/src/main/java/net/schueller/peertube/activity/ServerAddressBookActivity.kt new file mode 100644 index 0000000..3c55cfa --- /dev/null +++ b/app/src/main/java/net/schueller/peertube/activity/ServerAddressBookActivity.kt @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2020 Stefan Schüller + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package net.schueller.peertube.activity + +import android.app.Activity +import android.app.AlertDialog +import android.content.DialogInterface +import android.content.Intent +import android.os.Bundle +import android.util.Log +import android.widget.Toast +import androidx.activity.viewModels +import androidx.fragment.app.FragmentManager +import androidx.preference.PreferenceManager +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView +import net.schueller.peertube.R +import net.schueller.peertube.adapter.ServerListAdapter +import net.schueller.peertube.database.Server +import net.schueller.peertube.database.ServerViewModel +import net.schueller.peertube.databinding.ActivityServerAddressBookBinding +import net.schueller.peertube.fragment.AddServerFragment +import net.schueller.peertube.helper.APIUrlHelper +import net.schueller.peertube.network.Session +import net.schueller.peertube.service.LoginService +import java.util.* + +class ServerAddressBookActivity : CommonActivity() { + + private val TAG = "ServerAddressBookActivity" + + private val mServerViewModel: ServerViewModel by viewModels() + private var addServerFragment: AddServerFragment? = null + + private val fragmentManager: FragmentManager by lazy { supportFragmentManager } + + + private lateinit var mBinding: ActivityServerAddressBookBinding + + + override fun onSupportNavigateUp(): Boolean { + finish() // close this activity as oppose to navigating up + return false + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + mBinding = ActivityServerAddressBookBinding.inflate(layoutInflater) + setContentView(mBinding.root) + + // Setting toolbar as the ActionBar with setSupportActionBar() call + setSupportActionBar(mBinding.toolBarServerAddressBook) + supportActionBar?.apply { + setDisplayHomeAsUpEnabled(true) + setHomeAsUpIndicator(R.drawable.ic_baseline_close_24) + } + + + showServers() + + mBinding.addServer.setOnClickListener { + Log.d(TAG, "Click") + + val fragmentTransaction = fragmentManager.beginTransaction() + addServerFragment = AddServerFragment().also { + fragmentTransaction.replace(R.id.server_book, it) + fragmentTransaction.commit() + mBinding.addServer.hide() + } + } + } + + private fun onServerClick(server: Server) { + + val sharedPref = PreferenceManager.getDefaultSharedPreferences(this) + val editor = sharedPref.edit() + val serverUrl = APIUrlHelper.cleanServerUrl(server.serverHost) + editor.putString(getString(R.string.pref_api_base_key), serverUrl) + editor.apply() + + // Logout if logged in + val session = Session.getInstance() + if (session.isLoggedIn) { + session.invalidate() + } + + // attempt authentication if we have a username + if (server.username.isNullOrBlank().not()) { + LoginService.Authenticate(server.username, server.password) + } + + // close this activity + finish() + Toast.makeText(this, getString(R.string.server_selection_set_server, serverUrl), Toast.LENGTH_LONG).show() + } + + private fun onEditClick(server: Server) { + val fragmentTransaction = fragmentManager.beginTransaction() + addServerFragment = AddServerFragment.newInstance(server).also { + fragmentTransaction.replace(R.id.server_book, it) + fragmentTransaction.commit() + mBinding.addServer.hide() + } + } + + private fun showServers() { + val adapter = ServerListAdapter(mutableListOf(), { onServerClick(it) }, { onEditClick(it) }).also { + mBinding.serverListRecyclerview.adapter = it + } + + // Delete items on swipe + val helper = ItemTouchHelper( + object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) { + override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean { + return false + } + + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + AlertDialog.Builder(this@ServerAddressBookActivity) + .setTitle(getString(R.string.server_book_del_alert_title)) + .setMessage(getString(R.string.server_book_del_alert_msg)) + .setPositiveButton(android.R.string.yes) { _: DialogInterface?, _: Int -> + val position = viewHolder.adapterPosition + val server = adapter.getServerAtPosition(position) +// Toast.makeText(ServerAddressBookActivity.this, "Deleting " + +// server.getServerName(), Toast.LENGTH_LONG).show(); + // Delete the server + mServerViewModel.delete(server) + } + .setNegativeButton(android.R.string.no) { _: DialogInterface?, _: Int -> adapter.notifyItemChanged(viewHolder.adapterPosition) } + .setIcon(android.R.drawable.ic_dialog_alert) + .show() + } + }) + helper.attachToRecyclerView(mBinding.serverListRecyclerview) + + + // Update the cached copy of the words in the adapter. + mServerViewModel.allServers.observe(this, { servers: List -> + adapter.setServers(servers) + + addServerFragment?.let { + val fragmentTransaction = fragmentManager.beginTransaction() + fragmentTransaction.remove(it) + fragmentTransaction.commit() + mBinding.addServer.show() + } + }) + } + + companion object { + const val EXTRA_REPLY = "net.schueller.peertube.room.REPLY" + } +} \ No newline at end of file diff --git a/app/src/main/java/net/schueller/peertube/activity/SettingsActivity.java b/app/src/main/java/net/schueller/peertube/activity/SettingsActivity.java index 52db457..147a3c6 100644 --- a/app/src/main/java/net/schueller/peertube/activity/SettingsActivity.java +++ b/app/src/main/java/net/schueller/peertube/activity/SettingsActivity.java @@ -1,32 +1,36 @@ /* - * Copyright 2018 Stefan Schüller + * Copyright (C) 2020 Stefan Schüller * - * License: GPL-3.0+ * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ package net.schueller.peertube.activity; +import android.content.SharedPreferences; import android.os.Bundle; +import android.preference.PreferenceManager; +import android.util.Log; import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AlertDialog.Builder; import androidx.appcompat.widget.Toolbar; +import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.SwitchPreference; +import net.schueller.peertube.BuildConfig; import net.schueller.peertube.R; -import java.util.Objects; - public class SettingsActivity extends CommonActivity { @Override @@ -38,16 +42,72 @@ public class SettingsActivity extends CommonActivity { .beginTransaction() .replace(R.id.settings, new SettingsFragment()) .commit(); + + // Attaching the layout to the toolbar object + Toolbar toolbar = findViewById(R.id.tool_bar_settings); + // Setting toolbar as the ActionBar with setSupportActionBar() call + setSupportActionBar(toolbar); + ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setHomeAsUpIndicator(R.drawable.ic_baseline_close_24); } } + @Override + public boolean onSupportNavigateUp() { + finish(); // close this activity as oppose to navigating up + return false; + } + public static class SettingsFragment extends PreferenceFragmentCompat { @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { setPreferencesFromResource(R.xml.root_preferences, rootKey); + + // write Build Time into pref + Preference pref = findPreference("pref_buildtime"); + assert pref != null; + pref.setSummary(Long.toString(BuildConfig.BUILD_TIME)); + + // double check disabling SSL + final SwitchPreference insecure = (SwitchPreference) findPreference("pref_accept_insecure"); + if (insecure != null) { + insecure.setOnPreferenceChangeListener((preference, newValue) -> { + + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext()); + SharedPreferences.Editor editor = sharedPref.edit(); + + boolean currentValue = sharedPref.getBoolean("pref_accept_insecure", false); + + if (newValue instanceof Boolean && ((Boolean) newValue) != currentValue) { + final boolean enable = (Boolean) newValue; + + Log.v("pref", "enable: " + enable); + Log.v("pref", "currentValue: " + currentValue); + + if (enable) { + new Builder(preference.getContext()) + .setTitle(R.string.pref_insecure_confirm_title) + .setMessage(R.string.pref_insecure_confirm_message) + .setIcon(R.drawable.ic_info_black_24dp) + .setNegativeButton(R.string.pref_insecure_confirm_no, (dialog, whichButton) -> { + // do nothing + }) + .setPositiveButton(R.string.pref_insecure_confirm_yes, (dialog, whichButton) -> { + // OK has been pressed => force the new value and update the checkbox display + editor.putBoolean("pref_accept_insecure", true); + editor.apply(); + insecure.setChecked(true); + }).create().show(); + // by default ignore the pref change, which can only be validated when OK is pressed + return false; + } + } + return true; + }); + } } } } \ No newline at end of file diff --git a/app/src/main/java/net/schueller/peertube/activity/VideoListActivity.java b/app/src/main/java/net/schueller/peertube/activity/VideoListActivity.java index c4ca315..a760c4a 100644 --- a/app/src/main/java/net/schueller/peertube/activity/VideoListActivity.java +++ b/app/src/main/java/net/schueller/peertube/activity/VideoListActivity.java @@ -1,19 +1,18 @@ /* - * Copyright 2018 Stefan Schüller + * Copyright (C) 2020 Stefan Schüller * - * License: GPL-3.0+ * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ package net.schueller.peertube.activity; @@ -50,7 +49,6 @@ import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; @@ -60,6 +58,8 @@ import com.mikepenz.iconics.IconicsDrawable; import net.schueller.peertube.R; import net.schueller.peertube.adapter.VideoAdapter; import net.schueller.peertube.helper.APIUrlHelper; +import net.schueller.peertube.helper.ErrorHelper; +import net.schueller.peertube.model.Video; import net.schueller.peertube.model.VideoList; import net.schueller.peertube.network.GetUserService; import net.schueller.peertube.network.GetVideoDataService; @@ -70,6 +70,8 @@ import net.schueller.peertube.service.VideoPlayerService; import java.util.ArrayList; +import java.util.HashSet; +import java.util.Locale; import java.util.Set; import retrofit2.Call; @@ -320,17 +322,24 @@ public class VideoListActivity extends CommonActivity { isLoading = true; SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); - String nsfw = sharedPref.getBoolean("pref_show_nsfw", false) ? "both" : "false"; - Set languages = sharedPref.getStringSet("pref_language", null); + String nsfw = sharedPref.getBoolean(getString(R.string.pref_show_nsfw_key), false) ? "both" : "false"; + + Locale locale = getResources().getConfiguration().locale; + String country = locale.getLanguage(); + + HashSet countries = new HashSet<>(1); + countries.add(country); + + Set languages = sharedPref.getStringSet(getString(R.string.pref_video_language_key), countries); String apiBaseURL = APIUrlHelper.getUrlWithVersion(this); - GetVideoDataService service = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(GetVideoDataService.class); + GetVideoDataService service = RetrofitInstance.getRetrofitInstance(apiBaseURL, APIUrlHelper.useInsecureConnection(this)).create(GetVideoDataService.class); Call call; if (!searchQuery.equals("")) { call = service.searchVideosData(start, count, sort, nsfw, searchQuery, filter, languages); } else if (subscriptions) { - GetUserService userService = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(GetUserService.class); + GetUserService userService = RetrofitInstance.getRetrofitInstance(apiBaseURL, APIUrlHelper.useInsecureConnection(this)).create(GetUserService.class); call = userService.getVideosSubscripions(start, count, sort); } else { call = service.getVideosData(start, count, sort, nsfw, filter, languages); @@ -349,7 +358,10 @@ public class VideoListActivity extends CommonActivity { } if (response.body() != null) { - videoAdapter.setData(response.body().getVideoArrayList()); + ArrayList