diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..20be224 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,76 @@ +name: Build RPMs + +on: + push: + tags: + - "1.*" + +env: + OS_VERSION: 4.4.0.68 + +jobs: + build: + runs-on: ubuntu-latest + name: Build App + strategy: + matrix: + arch: ['armv7hl', 'aarch64', 'i486'] + + steps: + - uses: actions/checkout@v2 + + - name: Prepare + run: docker pull coderus/sailfishos-platform-sdk:$OS_VERSION && mkdir output + + - name: Build ${{ matrix.arch }} + run: docker run --rm --privileged -v $PWD:/share coderus/sailfishos-platform-sdk:$OS_VERSION /bin/bash -c " + mkdir -p build ; + cd build ; + cp -r /share/* . ; + mb2 -t SailfishOS-$OS_VERSION-${{ matrix.arch }} build ; + sudo cp -r RPMS/*.rpm /share/output" + + - name: Upload RPM (${{ matrix.arch }}) + uses: actions/upload-artifact@v2 + with: + name: rpm-${{ matrix.arch }} + path: output + release: + name: Release + if: startsWith(github.ref, 'refs/tags/1.1') + needs: + - build + runs-on: ubuntu-latest + steps: + - name: Download armv7hl + uses: actions/download-artifact@v2 + with: + name: rpm-armv7hl + continue-on-error: true + - name: Download aarch64 + uses: actions/download-artifact@v2 + with: + name: rpm-aarch64 + continue-on-error: true + - name: Download i486 + uses: actions/download-artifact@v2 + with: + name: rpm-i486 + continue-on-error: true + - name: Extract Version Name + id: extract_name + uses: actions/github-script@v4 + with: + result-encoding: string + script: | + return context.payload.ref.replace(/refs\/tags\//, ''); + - name: Create a Release + uses: softprops/action-gh-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + name: ${{ steps.extract_name.outputs.result }} + draft: false + prerelease: false + body: This release was autogenerated. + files: '*.rpm' diff --git a/harbour-tooterb.pro b/harbour-tooterb.pro index 7401286..8b6193e 100644 --- a/harbour-tooterb.pro +++ b/harbour-tooterb.pro @@ -68,6 +68,7 @@ DISTFILES += qml/harbour-tooterb.qml \ qml/pages/components/MyList.qml \ qml/pages/components/ProfileHeader.qml \ qml/pages/components/MediaBlock.qml \ + qml/pages/components/MediaItem.qml \ qml/cover/CoverPage.qml \ qml/pages/MainPage.qml \ qml/pages/LoginPage.qml \ @@ -87,7 +88,6 @@ DISTFILES += qml/harbour-tooterb.qml \ rpm/harbour-tooterb.changes \ rpm/harbour-tooterb.changes.run.in \ rpm/harbour-tooterb.spec \ - rpm/harbour-tooterb.yaml \ translations/*.ts \ harbour-tooterb.desktop diff --git a/harbour-tooterb.pro.user b/harbour-tooterb.pro.user index 3519283..b79aa86 100644 --- a/harbour-tooterb.pro.user +++ b/harbour-tooterb.pro.user @@ -1,1532 +1,1269 @@ - - - - - - EnvironmentId - {1eb0406f-b7ad-49c3-808f-08b8e70e23f1} - - - ProjectExplorer.Project.ActiveTarget - 0 - - - ProjectExplorer.Project.EditorSettings - - true - false - true - - Cpp - - CppGlobal - - - - QmlJS - - QmlJSGlobal - - - 2 - UTF-8 - false - 4 - false - 80 - true - true - 1 - true - false - 0 - true - true - 0 - 8 - true - 1 - true - true - true - false - - - - ProjectExplorer.Project.PluginSettings - - - -fno-delayed-template-parsing - - true - - - - ProjectExplorer.Project.Target.0 - - SailfishOS-3.2.1.20-i486 (in Sailfish OS Build Engine) - SailfishOS-3.2.1.20-i486 (in Sailfish OS Build Engine) - SailfishOS-3.2.1.20-i486 - 1 - 1 - 0 - - C:/Users/XPAM/Github/Github-App/build-harbour-tooterb-SailfishOS_3_2_1_20_i486_in_Sailfish_OS_Build_Engine-Debug - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - qmake - - QtProjectManager.QMakeBuildStep - true - - false - false - false - - - true - Make - - Qt4ProjectManager.MakeStep - - false - - - false - - 3 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - Make - - Qt4ProjectManager.MakeStep - - true - clean - - false - - 2 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Debug - Debug - Qt4ProjectManager.Qt4BuildConfiguration - 2 - true - - - C:/Users/XPAM/Github/Github-App/build-harbour-tooterb-SailfishOS_3_2_1_20_i486_in_Sailfish_OS_Build_Engine-Release - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - qmake - - QtProjectManager.QMakeBuildStep - false - - false - false - false - - - true - Make - - Qt4ProjectManager.MakeStep - - false - - - false - - 3 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - Make - - Qt4ProjectManager.MakeStep - - true - clean - - false - - 2 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Release - Release - Qt4ProjectManager.Qt4BuildConfiguration - 0 - true - - - C:/Users/XPAM/Github/Github-App/build-harbour-tooterb-SailfishOS_3_2_1_20_i486_in_Sailfish_OS_Build_Engine-Profile - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - qmake - - QtProjectManager.QMakeBuildStep - true - - false - true - false - - - true - Make - - Qt4ProjectManager.MakeStep - - false - - - false - - 3 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - Make - - Qt4ProjectManager.MakeStep - - true - clean - - false - - 2 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Profile - Profile - Qt4ProjectManager.Qt4BuildConfiguration - 0 - true - - 3 - - - - true - Prepare Target - - QmakeProjectManager.MerPrepareTargetStep - - - true - RPM - - QmakeProjectManager.MerRpmDeployStep - - 2 - Deploy - - ProjectExplorer.BuildSteps.Deploy - - 1 - Deploy As RPM Package - - QmakeProjectManager.MerRpmDeployConfiguration - - - - - true - RPM - - QmakeProjectManager.MerRpmBuildStep - - - true - RPM Validation - - QmakeProjectManager.MerRpmValidationStep - - 2 - Deploy - - ProjectExplorer.BuildSteps.Deploy - - 1 - Build RPM Package For Manual Deployment - - QmakeProjectManager.MerMb2RpmBuildConfiguration - - - - - true - Prepare Target - - QmakeProjectManager.MerPrepareTargetStep - - - true - Rsync - - QmakeProjectManager.MerRsyncDeployStep - - 2 - Deploy - - ProjectExplorer.BuildSteps.Deploy - - 1 - Deploy By Copying Binaries - - QmakeProjectManager.MerRSyncDeployConfiguration - - 3 - - - dwarf - - cpu-cycles - - - 250 - -F - true - 4096 - false - false - 1000 - - true - - false - false - false - false - true - 0.01 - 10 - true - kcachegrind - 1 - 25 - - 1 - true - false - true - valgrind - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - C:/Users/XPAM/Github/Github-App/harbour-tooter - false - -1 - 3 - - 1 - - - harbour-tooterb (on Sailfish OS Emulator 3.3.0.16) - QmakeProjectManager.MerRunConfiguration:C:/Users/XPAM/Github/Github-App/harbour-tooter/harbour-tooterb.pro - 1 - - false - - 3768 - false - true - false - false - true - - - - 1 - - - - ProjectExplorer.Project.Target.1 - - SailfishOS-3.3.0.16-armv7hl (in Sailfish OS Build Engine) - SailfishOS-3.3.0.16-armv7hl (in Sailfish OS Build Engine) - SailfishOS-3.3.0.16-armv7hl - 1 - 1 - 0 - - C:/Users/XPAM/Github/Github-App/build-harbour-tooterb-SailfishOS_3_3_0_16_armv7hl_in_Sailfish_OS_Build_Engine-Debug - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - qmake - - QtProjectManager.QMakeBuildStep - true - - false - false - false - - - true - Make - - Qt4ProjectManager.MakeStep - - false - - - false - - 3 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - Make - - Qt4ProjectManager.MakeStep - - true - clean - - false - - 2 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Debug - Debug - Qt4ProjectManager.Qt4BuildConfiguration - 2 - true - - - C:/Users/XPAM/Github/Github-App/build-harbour-tooterb-SailfishOS_3_3_0_16_armv7hl_in_Sailfish_OS_Build_Engine-Release - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - qmake - - QtProjectManager.QMakeBuildStep - false - - false - false - false - - - true - Make - - Qt4ProjectManager.MakeStep - - false - - - false - - 3 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - Make - - Qt4ProjectManager.MakeStep - - true - clean - - false - - 2 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Release - Release - Qt4ProjectManager.Qt4BuildConfiguration - 0 - true - - - C:/Users/XPAM/Github/Github-App/build-harbour-tooterb-SailfishOS_3_3_0_16_armv7hl_in_Sailfish_OS_Build_Engine-Profile - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - qmake - - QtProjectManager.QMakeBuildStep - true - - false - true - false - - - true - Make - - Qt4ProjectManager.MakeStep - - false - - - false - - 3 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - Make - - Qt4ProjectManager.MakeStep - - true - clean - - false - - 2 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Profile - Profile - Qt4ProjectManager.Qt4BuildConfiguration - 0 - true - - 3 - - - - true - Prepare Target - - QmakeProjectManager.MerPrepareTargetStep - - - true - RPM - - QmakeProjectManager.MerRpmDeployStep - - 2 - Deploy - - ProjectExplorer.BuildSteps.Deploy - - 1 - Deploy As RPM Package - - QmakeProjectManager.MerRpmDeployConfiguration - - - - - true - RPM - - QmakeProjectManager.MerRpmBuildStep - - - true - RPM Validation - - QmakeProjectManager.MerRpmValidationStep - - 2 - Deploy - - ProjectExplorer.BuildSteps.Deploy - - 1 - Build RPM Package For Manual Deployment - - QmakeProjectManager.MerMb2RpmBuildConfiguration - - - - - true - Prepare Target - - QmakeProjectManager.MerPrepareTargetStep - - - true - Rsync - - QmakeProjectManager.MerRsyncDeployStep - - 2 - Deploy - - ProjectExplorer.BuildSteps.Deploy - - 1 - Deploy By Copying Binaries - - QmakeProjectManager.MerRSyncDeployConfiguration - - 3 - - - dwarf - - cpu-cycles - - - 250 - -F - true - 4096 - false - false - 1000 - - true - - false - false - false - false - true - 0.01 - 10 - true - kcachegrind - 1 - 25 - - 1 - true - false - true - valgrind - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - C:/Users/XPAM/Github/Github-App/harbour-tooter - false - -1 - 3 - - 1 - - - harbour-tooterb (on Sailfish OS Emulator 3.3.0.16) - QmakeProjectManager.MerRunConfiguration:C:/Users/XPAM/Github/Github-App/harbour-tooter/harbour-tooterb.pro - 1 - - false - - 3768 - false - true - false - false - true - - - - 1 - - - - ProjectExplorer.Project.Target.2 - - SailfishOS-3.3.0.16-i486 (in Sailfish OS Build Engine) - SailfishOS-3.3.0.16-i486 (in Sailfish OS Build Engine) - SailfishOS-3.3.0.16-i486 - 1 - 2 - 0 - - C:/Users/XPAM/Github/Github-App/build-harbour-tooterb-SailfishOS_3_3_0_16_i486_in_Sailfish_OS_Build_Engine-Debug - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - qmake - - QtProjectManager.QMakeBuildStep - true - - false - false - false - - - true - Make - - Qt4ProjectManager.MakeStep - - false - - - false - - 3 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - Make - - Qt4ProjectManager.MakeStep - - true - clean - - false - - 2 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Debug - Debug - Qt4ProjectManager.Qt4BuildConfiguration - 2 - true - - - C:/Users/XPAM/Github/Github-App/build-harbour-tooterb-SailfishOS_3_3_0_16_i486_in_Sailfish_OS_Build_Engine-Release - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - qmake - - QtProjectManager.QMakeBuildStep - false - - false - false - false - - - true - Make - - Qt4ProjectManager.MakeStep - - false - - - false - - 3 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - Make - - Qt4ProjectManager.MakeStep - - true - clean - - false - - 2 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Release - Release - Qt4ProjectManager.Qt4BuildConfiguration - 0 - true - - - C:/Users/XPAM/Github/Github-App/build-harbour-tooterb-SailfishOS_3_3_0_16_i486_in_Sailfish_OS_Build_Engine-Profile - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - qmake - - QtProjectManager.QMakeBuildStep - true - - false - true - false - - - true - Make - - Qt4ProjectManager.MakeStep - - false - - - false - - 3 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - Make - - Qt4ProjectManager.MakeStep - - true - clean - - false - - 2 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Profile - Profile - Qt4ProjectManager.Qt4BuildConfiguration - 0 - true - - 3 - - - - true - Prepare Target - - QmakeProjectManager.MerPrepareTargetStep - - - true - RPM - - QmakeProjectManager.MerRpmDeployStep - - 2 - Deploy - - ProjectExplorer.BuildSteps.Deploy - - 1 - Deploy As RPM Package - - QmakeProjectManager.MerRpmDeployConfiguration - - - - - true - RPM - - QmakeProjectManager.MerRpmBuildStep - - - true - RPM Validation - - QmakeProjectManager.MerRpmValidationStep - - 2 - Deploy - - ProjectExplorer.BuildSteps.Deploy - - 1 - Build RPM Package For Manual Deployment - - QmakeProjectManager.MerMb2RpmBuildConfiguration - - - - - true - Prepare Target - - QmakeProjectManager.MerPrepareTargetStep - - - true - Rsync - - QmakeProjectManager.MerRsyncDeployStep - - 2 - Deploy - - ProjectExplorer.BuildSteps.Deploy - - 1 - Deploy By Copying Binaries - - QmakeProjectManager.MerRSyncDeployConfiguration - - 3 - - - dwarf - - cpu-cycles - - - 250 - -F - true - 4096 - false - false - 1000 - - true - - false - false - false - false - true - 0.01 - 10 - true - kcachegrind - 1 - 25 - - 1 - true - false - true - valgrind - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - C:/Users/XPAM/Github/Github-App/harbour-tooter - false - -1 - 3 - - 1 - - - harbour-tooterb (on Sailfish OS Emulator 3.3.0.16) - QmakeProjectManager.MerRunConfiguration:C:/Users/XPAM/Github/Github-App/harbour-tooter/harbour-tooterb.pro - 1 - - false - - 3768 - false - true - false - false - true - - - - 1 - - - - ProjectExplorer.Project.Target.3 - - SailfishOS-3.2.1.20-armv7hl (in Sailfish OS Build Engine) - SailfishOS-3.2.1.20-armv7hl (in Sailfish OS Build Engine) - SailfishOS-3.2.1.20-armv7hl - 1 - 1 - 0 - - C:/Users/XPAM/Github/Github-App/build-harbour-tooterb-SailfishOS_3_2_1_20_armv7hl_in_Sailfish_OS_Build_Engine-Debug - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - qmake - - QtProjectManager.QMakeBuildStep - true - - false - false - false - - - true - Make - - Qt4ProjectManager.MakeStep - - false - - - false - - 3 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - Make - - Qt4ProjectManager.MakeStep - - true - clean - - false - - 2 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Debug - Debug - Qt4ProjectManager.Qt4BuildConfiguration - 2 - true - - - C:/Users/XPAM/Github/Github-App/build-harbour-tooterb-SailfishOS_3_2_1_20_armv7hl_in_Sailfish_OS_Build_Engine-Release - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - qmake - - QtProjectManager.QMakeBuildStep - false - - false - false - false - - - true - Make - - Qt4ProjectManager.MakeStep - - false - - - false - - 3 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - Make - - Qt4ProjectManager.MakeStep - - true - clean - - false - - 2 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Release - Release - Qt4ProjectManager.Qt4BuildConfiguration - 0 - true - - - C:/Users/XPAM/Github/Github-App/build-harbour-tooterb-SailfishOS_3_2_1_20_armv7hl_in_Sailfish_OS_Build_Engine-Profile - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - qmake - - QtProjectManager.QMakeBuildStep - true - - false - true - false - - - true - Make - - Qt4ProjectManager.MakeStep - - false - - - false - - 3 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - Start Build Engine - - Mer.MerSdkStartStep - - - true - Make - - Qt4ProjectManager.MakeStep - - true - clean - - false - - 2 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Profile - Profile - Qt4ProjectManager.Qt4BuildConfiguration - 0 - true - - 3 - - - - true - Prepare Target - - QmakeProjectManager.MerPrepareTargetStep - - - true - RPM - - QmakeProjectManager.MerRpmDeployStep - - 2 - Deploy - - ProjectExplorer.BuildSteps.Deploy - - 1 - Deploy As RPM Package - - QmakeProjectManager.MerRpmDeployConfiguration - - - - - true - RPM - - QmakeProjectManager.MerRpmBuildStep - - - true - RPM Validation - - QmakeProjectManager.MerRpmValidationStep - - 2 - Deploy - - ProjectExplorer.BuildSteps.Deploy - - 1 - Build RPM Package For Manual Deployment - - QmakeProjectManager.MerMb2RpmBuildConfiguration - - - - - true - Prepare Target - - QmakeProjectManager.MerPrepareTargetStep - - - true - Rsync - - QmakeProjectManager.MerRsyncDeployStep - - 2 - Deploy - - ProjectExplorer.BuildSteps.Deploy - - 1 - Deploy By Copying Binaries - - QmakeProjectManager.MerRSyncDeployConfiguration - - 3 - - - dwarf - - cpu-cycles - - - 250 - -F - true - 4096 - false - false - 1000 - - true - - false - false - false - false - true - 0.01 - 10 - true - kcachegrind - 1 - 25 - - 1 - true - false - true - valgrind - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - C:/Users/XPAM/Github/Github-App/harbour-tooter - false - -1 - 3 - - 1 - - - harbour-tooterb (on Sailfish OS Emulator 3.3.0.16) - QmakeProjectManager.MerRunConfiguration:C:/Users/XPAM/Github/Github-App/harbour-tooter/harbour-tooterb.pro - 1 - - false - - 3768 - false - true - false - false - true - - - - 1 - - - - ProjectExplorer.Project.TargetCount - 4 - - - ProjectExplorer.Project.Updater.FileVersion - 21 - - - Version - 21 - - + + + + + + EnvironmentId + {ddbad1fa-3e15-4c49-99dc-7ab87bce53d2} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + false + true + false + 0 + true + true + 0 + 8 + true + false + 1 + true + true + true + *.md, *.MD, Makefile + false + true + + + + ProjectExplorer.Project.PluginSettings + + + true + false + true + true + true + true + + + 0 + true + + true + Builtin.BuildSystem + + true + true + Builtin.DefaultTidyAndClazy + 4 + + + + true + + + + + ProjectExplorer.Project.Target.0 + + Mer.Device.Type + SailfishOS-4.4.0.58-aarch64 (in Sailfish SDK Build Engine) + SailfishOS-4.4.0.58-aarch64 (in Sailfish SDK Build Engine) + SailfishOS-4.4.0.58-aarch64.default + 1 + 0 + 0 + + 0 + false + + + + + /home/mwa/src/sailfish/build-harbour-tooterb-SailfishOS_4_4_0_58_aarch64_in_Sailfish_SDK_Build_Engine-Debug + /home/mwa/src/sailfish/build-harbour-tooterb-SailfishOS_4_4_0_58_aarch64_in_Sailfish_SDK_Build_Engine-Debug + + + true + Mer.MerSdkStartStep + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 3 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Mer.MerSdkStartStep + + + reset + true + Mer.MerClearBuildEnvironmentStep + + + true + Qt4ProjectManager.MakeStep + clean + + 3 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Debug + Qt4ProjectManager.Qt4BuildConfiguration + 2 + 1 + + + false + + + + + /home/mwa/src/sailfish/build-harbour-tooterb-SailfishOS_4_4_0_58_aarch64_in_Sailfish_SDK_Build_Engine-Release + /home/mwa/src/sailfish/build-harbour-tooterb-SailfishOS_4_4_0_58_aarch64_in_Sailfish_SDK_Build_Engine-Release + + + true + Mer.MerSdkStartStep + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 3 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Mer.MerSdkStartStep + + + reset + true + Mer.MerClearBuildEnvironmentStep + + + true + Qt4ProjectManager.MakeStep + clean + + 3 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Release + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 1 + + + 0 + false + + + + + /home/mwa/src/sailfish/build-harbour-tooterb-SailfishOS_4_4_0_58_aarch64_in_Sailfish_SDK_Build_Engine-Profile + /home/mwa/src/sailfish/build-harbour-tooterb-SailfishOS_4_4_0_58_aarch64_in_Sailfish_SDK_Build_Engine-Profile + + + true + Mer.MerSdkStartStep + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 3 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Mer.MerSdkStartStep + + + reset + true + Mer.MerClearBuildEnvironmentStep + + + true + Qt4ProjectManager.MakeStep + clean + + 3 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Profile + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 1 + 0 + + 3 + + + + true + QmakeProjectManager.MerPrepareTargetStep + + + true + QmakeProjectManager.MerRpmBuildStep + + + --sdk + true + QmakeProjectManager.MerRpmDeployStep + + 3 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + QmakeProjectManager.MerRpmDeployConfiguration + + + + + true + QmakeProjectManager.MerRpmBuildStep + + + true + QmakeProjectManager.MerRpmValidationStep + + 2 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + QmakeProjectManager.MerMb2RpmBuildConfiguration + + + + + true + QmakeProjectManager.MerPrepareTargetStep + + + true + QmakeProjectManager.MerMakeInstallBuildStep + + + --rsync + true + QmakeProjectManager.MerRsyncDeployStep + + 3 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + QmakeProjectManager.MerRSyncDeployConfiguration + + 3 + + dwarf + + cpu-cycles + + + 250 + + -e + cpu-cycles + --call-graph + dwarf,4096 + -F + 250 + + -F + true + 4096 + false + false + 1000 + + true + + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + + 25 + + 1 + true + false + true + + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + + true + /home/mwa/src/sailfish/harbour-tooter + true + -1 + 3 + + 1 + + harbour-tooterb (on %{Device:Name}) + QmakeProjectManager.MerRunConfiguration:/home/mwa/src/sailfish/harbour-tooter/harbour-tooterb.pro + /home/mwa/src/sailfish/harbour-tooter/harbour-tooterb.pro + 1 + false + true + false + true + :0.0 + + 1 + + + + ProjectExplorer.Project.Target.1 + + Mer.Device.Type + SailfishOS-4.4.0.58-armv7hl (in Sailfish SDK Build Engine) + SailfishOS-4.4.0.58-armv7hl (in Sailfish SDK Build Engine) + SailfishOS-4.4.0.58-armv7hl.default + 0 + 0 + 0 + + 0 + false + + + + + /home/mwa/src/sailfish/build-harbour-tooterb-SailfishOS_4_4_0_58_armv7hl_in_Sailfish_SDK_Build_Engine-Debug + /home/mwa/src/sailfish/build-harbour-tooterb-SailfishOS_4_4_0_58_armv7hl_in_Sailfish_SDK_Build_Engine-Debug + + + true + Mer.MerSdkStartStep + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 3 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Mer.MerSdkStartStep + + + reset + true + Mer.MerClearBuildEnvironmentStep + + + true + Qt4ProjectManager.MakeStep + clean + + 3 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Debug + Qt4ProjectManager.Qt4BuildConfiguration + 2 + 1 + + + false + + + + + /home/mwa/src/sailfish/build-harbour-tooterb-SailfishOS_4_4_0_58_armv7hl_in_Sailfish_SDK_Build_Engine-Release + /home/mwa/src/sailfish/build-harbour-tooterb-SailfishOS_4_4_0_58_armv7hl_in_Sailfish_SDK_Build_Engine-Release + + + true + Mer.MerSdkStartStep + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 3 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Mer.MerSdkStartStep + + + reset + true + Mer.MerClearBuildEnvironmentStep + + + true + Qt4ProjectManager.MakeStep + clean + + 3 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Release + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 1 + + + 0 + false + + + + + /home/mwa/src/sailfish/build-harbour-tooterb-SailfishOS_4_4_0_58_armv7hl_in_Sailfish_SDK_Build_Engine-Profile + /home/mwa/src/sailfish/build-harbour-tooterb-SailfishOS_4_4_0_58_armv7hl_in_Sailfish_SDK_Build_Engine-Profile + + + true + Mer.MerSdkStartStep + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 3 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Mer.MerSdkStartStep + + + reset + true + Mer.MerClearBuildEnvironmentStep + + + true + Qt4ProjectManager.MakeStep + clean + + 3 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Profile + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 1 + 0 + + 3 + + + + true + QmakeProjectManager.MerPrepareTargetStep + + + true + QmakeProjectManager.MerRpmBuildStep + + + --sdk + true + QmakeProjectManager.MerRpmDeployStep + + 3 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + QmakeProjectManager.MerRpmDeployConfiguration + + + + + true + QmakeProjectManager.MerRpmBuildStep + + + true + QmakeProjectManager.MerRpmValidationStep + + 2 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + QmakeProjectManager.MerMb2RpmBuildConfiguration + + + + + true + QmakeProjectManager.MerPrepareTargetStep + + + true + QmakeProjectManager.MerMakeInstallBuildStep + + + --rsync + true + QmakeProjectManager.MerRsyncDeployStep + + 3 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + QmakeProjectManager.MerRSyncDeployConfiguration + + 3 + + dwarf + + cpu-cycles + + + 250 + + -e + cpu-cycles + --call-graph + dwarf,4096 + -F + 250 + + -F + true + 4096 + false + false + 1000 + + true + + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + + 25 + + 1 + true + false + true + + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + + true + /home/mwa/src/sailfish/harbour-tooter + false + -1 + 3 + + 1 + + harbour-tooterb (on %{Device:Name}) + QmakeProjectManager.MerRunConfiguration:/home/mwa/src/sailfish/harbour-tooter/harbour-tooterb.pro + /home/mwa/src/sailfish/harbour-tooter/harbour-tooterb.pro + 1 + false + true + false + true + :0.0 + + + dwarf + + cpu-cycles + + + 250 + + -e + cpu-cycles + --call-graph + dwarf,4096 + -F + 250 + + -F + true + 4096 + false + false + 1000 + + true + + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + + 25 + + 1 + true + false + true + + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + + true + /home/mwa/src/sailfish/harbour-tooter + false + -1 + 3 + + 1 + + harbour-tooterb + QmakeProjectManager.MerRunConfiguration:/home/mwa/src/sailfish/harbour-tooter/harbour-tooterb.pro + /home/mwa/src/sailfish/harbour-tooter/harbour-tooterb.pro + 1 + false + true + false + true + :0.0 + + 2 + + + + ProjectExplorer.Project.Target.2 + + Mer.Device.Type + SailfishOS-4.4.0.58-i486 (in Sailfish SDK Build Engine) + SailfishOS-4.4.0.58-i486 (in Sailfish SDK Build Engine) + SailfishOS-4.4.0.58-i486.default + 0 + 0 + 0 + + 0 + false + + + + + /home/mwa/src/sailfish/build-harbour-tooterb-SailfishOS_4_4_0_58_i486_in_Sailfish_SDK_Build_Engine-Debug + /home/mwa/src/sailfish/build-harbour-tooterb-SailfishOS_4_4_0_58_i486_in_Sailfish_SDK_Build_Engine-Debug + + + true + Mer.MerSdkStartStep + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 3 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Mer.MerSdkStartStep + + + reset + true + Mer.MerClearBuildEnvironmentStep + + + true + Qt4ProjectManager.MakeStep + clean + + 3 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Debug + Qt4ProjectManager.Qt4BuildConfiguration + 2 + 1 + + + false + + + + + /home/mwa/src/sailfish/build-harbour-tooterb-SailfishOS_4_4_0_58_i486_in_Sailfish_SDK_Build_Engine-Release + /home/mwa/src/sailfish/build-harbour-tooterb-SailfishOS_4_4_0_58_i486_in_Sailfish_SDK_Build_Engine-Release + + + true + Mer.MerSdkStartStep + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 3 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Mer.MerSdkStartStep + + + reset + true + Mer.MerClearBuildEnvironmentStep + + + true + Qt4ProjectManager.MakeStep + clean + + 3 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Release + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 1 + + + 0 + false + + + + + /home/mwa/src/sailfish/build-harbour-tooterb-SailfishOS_4_4_0_58_i486_in_Sailfish_SDK_Build_Engine-Profile + /home/mwa/src/sailfish/build-harbour-tooterb-SailfishOS_4_4_0_58_i486_in_Sailfish_SDK_Build_Engine-Profile + + + true + Mer.MerSdkStartStep + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 3 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Mer.MerSdkStartStep + + + reset + true + Mer.MerClearBuildEnvironmentStep + + + true + Qt4ProjectManager.MakeStep + clean + + 3 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Profile + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 1 + 0 + + 3 + + + + true + QmakeProjectManager.MerPrepareTargetStep + + + true + QmakeProjectManager.MerRpmBuildStep + + + --sdk + true + QmakeProjectManager.MerRpmDeployStep + + 3 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + QmakeProjectManager.MerRpmDeployConfiguration + + + + + true + QmakeProjectManager.MerRpmBuildStep + + 1 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + QmakeProjectManager.MerMb2RpmBuildConfiguration + + + + + true + QmakeProjectManager.MerPrepareTargetStep + + + true + QmakeProjectManager.MerMakeInstallBuildStep + + + --rsync + true + QmakeProjectManager.MerRsyncDeployStep + + 3 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + QmakeProjectManager.MerRSyncDeployConfiguration + + 3 + + dwarf + + cpu-cycles + + + 250 + + -e + cpu-cycles + --call-graph + dwarf,4096 + -F + 250 + + -F + true + 4096 + false + false + 1000 + + true + + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + + 25 + + 1 + true + false + true + + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + + true + /home/mwa/src/sailfish/harbour-tooter + false + -1 + 3 + + 2 + + ProjectExplorer.CustomExecutableRunConfiguration + + false + true + false + true + + + dwarf + + cpu-cycles + + + 250 + + -e + cpu-cycles + --call-graph + dwarf,4096 + -F + 250 + + -F + true + 4096 + false + false + 1000 + + true + + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + + 25 + + 1 + true + false + true + + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + + true + /home/mwa/src/sailfish/harbour-tooter + false + -1 + 3 + + 1 + + QmakeProjectManager.MerCustomRunConfiguration: + + 1 + false + true + false + true + :0.0 + + 2 + + + + ProjectExplorer.Project.TargetCount + 3 + + + ProjectExplorer.Project.Updater.FileVersion + 22 + + + Version + 22 + + diff --git a/qml/harbour-tooterb.qml b/qml/harbour-tooterb.qml index 60e8399..90838fa 100644 --- a/qml/harbour-tooterb.qml +++ b/qml/harbour-tooterb.qml @@ -67,6 +67,8 @@ ApplicationWindow { } }) Logic.init() + + } Component.onDestruction: { diff --git a/qml/lib/API.js b/qml/lib/API.js index cfc6fa8..0af167e 100644 --- a/qml/lib/API.js +++ b/qml/lib/API.js @@ -72,7 +72,7 @@ function saveData() { } } } - console.log("ENF OF SAVING") + console.log("END OF SAVING") }); } @@ -116,6 +116,8 @@ var modelTLpublic = Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt var modelTLlocal = Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject'); var modelTLnotifications = Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject'); var modelTLsearch = Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject'); +var modelTLbookmarks = Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject'); + var notificationsList = [] var notificationGenerator = function(item){ diff --git a/qml/lib/Mastodon.js b/qml/lib/Mastodon.js index 97b5bcc..f7c812e 100644 --- a/qml/lib/Mastodon.js +++ b/qml/lib/Mastodon.js @@ -16,6 +16,58 @@ var mastodonAPI = function(config) { return config[key]; }, + /* + * function to retrieve the Link header + * using HEAD, so bookmarks has head followed by GET + */ + + getLink: function (endpoint) { + // variables + var queryData, callback, + queryStringAppend = "?"; + + // check with which arguments we're supplied + if (typeof arguments[1] === "function") { + queryData = {}; + callback = arguments[1]; + } else { + queryData = arguments[1]; + callback = arguments[2]; + } + // build queryData Object into a URL Query String + for (var i in queryData) { + if (queryData.hasOwnProperty(i)) { + if (typeof queryData[i] === "string") { + queryStringAppend += queryData[i] + "&"; + } else if (typeof queryData[i] === "object") { + queryStringAppend += queryData[i].name + "="+ queryData[i].data + "&"; + } + } + } + var http = new XMLHttpRequest() + var url = apiBase + endpoint; + console.log("HEAD" + apiBase + endpoint + queryStringAppend) + + http.open("HEAD", apiBase + endpoint + queryStringAppend, true); + // Send the proper header information along with the request + http.setRequestHeader("Authorization", "Bearer " + config.api_user_token); + http.setRequestHeader("Content-Type", "application/json"); + http.setRequestHeader("Connection", "close"); + + http.onreadystatechange = function() { + if (http.readyState === 4) { + if (http.status === 200) { + callback( http.getResponseHeader("Link") , http.status) + console.log("Successful HEAD API request to " +apiBase+endpoint); + } else { + console.log("error: " + http.status) + } + } + } + http.send(); + + }, + get: function (endpoint) { // for GET API calls // can be called with two or three parameters @@ -46,10 +98,11 @@ var mastodonAPI = function(config) { } } } + //queryStringAppend += "limit=20" // ajax function var http = new XMLHttpRequest() var url = apiBase + endpoint; - console.log(queryStringAppend) + console.log(apiBase + endpoint + queryStringAppend) http.open("GET", apiBase + endpoint + queryStringAppend, true); // Send the proper header information along with the request @@ -60,8 +113,8 @@ var mastodonAPI = function(config) { http.onreadystatechange = function() { // Call a function when the state changes. if (http.readyState === 4) { if (http.status === 200) { - console.log("Successful GET API request to " +apiBase+endpoint); callback(JSON.parse(http.response),http.status) + console.log("Successful GET API request to " +apiBase+endpoint); } else { console.log("error: " + http.status) } @@ -219,7 +272,7 @@ var mastodonAPI = function(config) { var http = new XMLHttpRequest() var url = config.instance + "/oauth/token"; var params = 'client_id=' + client_id + '&client_secret=' + client_secret + '&redirect_uri=' + redirect_uri + '&grant_type=authorization_code&code=' + code; - console.log(params) + // console.log(params) http.open("POST", url, true); // Send the proper header information along with the request diff --git a/qml/lib/Worker.js b/qml/lib/Worker.js index 19b9ddd..c906c69 100644 --- a/qml/lib/Worker.js +++ b/qml/lib/Worker.js @@ -1,14 +1,40 @@ Qt.include("Mastodon.js") - +var debug = true; var loadImages = true; +// used to dedupe on append/insert +var knownIds = []; +var max_id ; +var since_id; WorkerScript.onMessage = function(msg) { +/* console.log("Action > " + msg.action) console.log("Model > " + msg.model) console.log("Mode > " + msg.mode) console.log("Conf > " + JSON.stringify(msg.conf)) console.log("Params > " + JSON.stringify(msg.params)) +*/ + + // this is not elegant. it's max_id and ids from MyList + + if (msg.params[1]) { + if ( msg.params[0]["name"] === "max_id" ) { + max_id = msg.params[0]["data"] + } else { + since_id = msg.params[0]["data"] + } + // we don't want to pass it onto the backend + if ( msg.params[1]["name"] === "ids" ) { + knownIds = msg.params[1]["data"] + msg.params.pop() + } + if ( msg.params[2]["name"] === "ids" ) { + knownIds = msg.params[2]["data"] + msg.params.pop() + } + } + /** order notifications in ASC order */ function orderNotifications(items){ @@ -20,7 +46,7 @@ WorkerScript.onMessage = function(msg) { /** Logged-in status */ if (!msg.conf || !msg.conf.login) { - console.log("Not loggedin") + //console.log("Not loggedin") return; } @@ -28,12 +54,30 @@ WorkerScript.onMessage = function(msg) { if (typeof msg.conf['loadImages'] !== "undefined") loadImages = msg.conf['loadImages'] - /** POST statuses */ + + /* init API statuses */ + var API = mastodonAPI({ instance: msg.conf.instance, api_user_token: msg.conf.api_user_token}); + + /* + * HEAD call for some actions + * we have to retrieve the Link header + * this falls through and continues for GET + */ + + if (msg.action === "bookmarks"){ + API.getLink(msg.action, msg.params, function(data) { + if (debug) console.log(JSON.stringify(data)) + WorkerScript.sendMessage({ 'LinkHeader': data }) + }); + } + + /** POST statuses */ + if (msg.method === "POST"){ API.post(msg.action, msg.params, function(data) { if (msg.bgAction){ - console.log(JSON.stringify(data)) + //console.log(JSON.stringify(data)) } else if (msg.action === "statuses") { // status posted if(msg.model){ @@ -45,7 +89,7 @@ WorkerScript.onMessage = function(msg) { } else { for (var i in data) { if (data.hasOwnProperty(i)) { - console.log(JSON.stringify(data[i])) + //console.log(JSON.stringify(data[i])) WorkerScript.sendMessage({ 'action': msg.action, 'success': true, key: i, "data": data[i]}) } } @@ -55,21 +99,26 @@ WorkerScript.onMessage = function(msg) { } API.get(msg.action, msg.params, function(data) { + var items = []; + //console.log(data) + for (var i in data) { var item; if (data.hasOwnProperty(i)) { if(msg.action === "accounts/search") { item = parseAccounts([], "", data[i]); - console.log(JSON.stringify(data[i])) + //console.log(JSON.stringify(data[i])) + console.log("has own data") + items.push(item) } else if(msg.action === "notifications") { // notification - console.log("Get notification list") - console.log(JSON.stringify(data[i])) + //console.log("Get notification list") + //console.log(JSON.stringify(data[i])) item = parseNotification(data[i]); - items.push(item) + items.push(item); } else if(msg.action.indexOf("statuses") >-1 && msg.action.indexOf("context") >-1 && i === "ancestors") { // status ancestors toots - conversation @@ -79,8 +128,9 @@ WorkerScript.onMessage = function(msg) { item['id'] = item['status_id']; if (typeof item['attachments'] === "undefined") item['attachments'] = []; - items.push(item) - console.log(JSON.stringify(data[i][j])) + // don't permit doubles + items.push(item); + //console.log(JSON.stringify(data[i][j])) } addDataToModel (msg.model, "prepend", items); items = []; @@ -94,8 +144,8 @@ WorkerScript.onMessage = function(msg) { item['id'] = item['status_id']; if (typeof item['attachments'] === "undefined") item['attachments'] = []; - items.push(item) - console.log(JSON.stringify(data[i][j])) + items.push(item); + //console.log(JSON.stringify(data[i][j])) } addDataToModel (msg.model, "append", items); items = []; @@ -104,7 +154,8 @@ WorkerScript.onMessage = function(msg) { //console.log("Get Toot") item = parseToot(data[i]); item['id'] = item['status_id'] - items.push(item) + items.push(item); + } else { WorkerScript.sendMessage({ 'action': msg.action, 'success': true, key: i, "data": data[i] }) @@ -112,29 +163,66 @@ WorkerScript.onMessage = function(msg) { } } - if(msg.model && items.length) + if(msg.model && items.length) { addDataToModel(msg.model, msg.mode, items) + } else { + // for some reason, home chokes. + console.log( "items.length = " + items.length) + } + /*if(msg.action === "notifications") orderNotifications(items)*/ + + console.log("Get em all?") + + WorkerScript.sendMessage({ 'updatedAll': true}) }); } //WorkerScript.sendMessage({ 'notifyNewItems': length - i }) + function addDataToModel (model, mode, items) { + var length = items.length; - console.log("Fetched > " +length) + var i + + if (debug) console.log("Fetched > " +length + " in " + mode) + if (debug) console.log("ids > " + knownIds.length ) if (mode === "append") { - model.append(items) + for(i = 0; i <= length-1; i++) { + if ( knownIds.indexOf( items[i]["id"]) === -1) { + model.append(items[i]) + } else { + console.log("nope: " + items[i]["id"] ) + } + } + // search does not use ids + if ( knownIds.length < 1 ) model.append(items) + } else if (mode === "prepend") { - for(var i = length-1; i >= 0 ; i--) { + for(i = length-1; i >= 0 ; i--) { + model.insert(0,items[i]) + + /*if ( knownIds.indexOf( items[i]["id"]) === -1) { + model.insert(0,items[i]) + }*/ } } model.sync() } -/** Function: Get Account Data */ +function findDuplicate(arr,val) { + for(var i=0; i < arr.length; i++){ + if( arr.indexOf(val) === -1 ) { + return true; + } + } + return false; +} + +/* Function: Get Account Data */ function parseAccounts(collection, prefix, data) { var res = collection; diff --git a/qml/pages/ConversationPage.qml b/qml/pages/ConversationPage.qml index f641278..36191b8 100644 --- a/qml/pages/ConversationPage.qml +++ b/qml/pages/ConversationPage.qml @@ -8,6 +8,7 @@ import "./components/" Page { id: conversationPage + property bool debug: false property ListModel suggestedModel property ListModel mdl property int tootMaxChar: 500 @@ -25,9 +26,11 @@ Page { property string status_link: if (status_url === "") { var test = status_uri.split("/") - console.log(status_uri) - console.log(JSON.stringify(test)) - console.log(JSON.stringify(test.length)) + if (debug) { + console.log(status_uri) + console.log(JSON.stringify(test)) + console.log(JSON.stringify(test.length)) + } if (test.length === 8 && (test[7] === "activity")) { var urialt = status_uri.replace("activity", "") status_link = urialt @@ -37,7 +40,7 @@ Page { allowedOrientations: Orientation.All onSuggestedUserChanged: { - console.log(suggestedUser) + //console.log(suggestedUser) suggestedModel = Qt.createQmlObject( 'import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject' ) predictionList.visible = false if (suggestedUser.length > 0) { @@ -67,7 +70,9 @@ Page { WorkerScript { id: worker source: "../lib/Worker.js" - onMessage: { console.log(JSON.stringify(messageObject)) } + onMessage: { + //console.log(JSON.stringify(messageObject)) + } } SilicaListView { @@ -98,7 +103,7 @@ Page { if (mdl) for (var i = 0; i < mdl.count; i++) { if (mdl.get(i).status_id === status_id) { - console.log(mdl.get(i).status_id) + //console.log(mdl.get(i).status_id) positionViewAtIndex(i, ListView.Center) } } @@ -266,7 +271,7 @@ Page { textOperations.select( textOperations.selectionStart ? textOperations.selectionStart - 1 : 0, textOperations.selectionEnd) - console.log(toot.text.length) + //console.log(toot.text.length) suggestedUser = "" if (textOperations.selectedText.charAt(0) === "@") { suggestedUser = textOperations.selectedText.trim().substring(1) @@ -292,7 +297,9 @@ Page { right: parent.right rightMargin: Theme.paddingSmall } - onSelectionChanged: { console.log(selection) } + onSelectionChanged: { + //console.log(selection) + } onClicked: pageStack.push(emojiDialog) } @@ -321,7 +328,7 @@ Page { } onClicked: { var idx = index - console.log(idx) + //console.log(idx) //mediaModel.remove(idx) remorse.execute(myDelegate, "", function () { mediaModel.remove(idx) @@ -381,7 +388,9 @@ Page { var imagePicker = pageStack.push("Sailfish.Pickers.ImagePickerPage", { "allowedOrientations": Orientation.All }) imagePicker.selectedContentChanged.connect(function () { var imagePath = imagePicker.selectedContent - console.log(imagePath) + + // console.log(imagePath) + imageUploader.setUploadUrl(Logic.conf.instance + "/api/v1/media") imageUploader.setFile(imagePath) imageUploader.setAuthorizationHeader(Logic.conf.api_user_token) @@ -393,19 +402,19 @@ Page { ImageUploader { id: imageUploader onProgressChanged: { - console.log("progress " + progress) + // console.log("progress " + progress) uploadProgress.width = parent.width * progress } onSuccess: { uploadProgress.width = 0 - console.log(replyData) + //console.log(replyData) mediaModel.append(JSON.parse(replyData)) } onFailure: { uploadProgress.width = 0 btnAddImage.enabled = true - console.log(status) - console.log(statusText) + //console.log(status) + //console.log(statusText) } } @@ -447,7 +456,7 @@ Page { var visibility = ["public", "unlisted", "private", "direct"] var media_ids = [] for (var k = 0; k < mediaModel.count; k++) { - console.log(mediaModel.get(k).id) + // console.log(mediaModel.get(k).id) media_ids.push(mediaModel.get(k).id) } var msg = { @@ -511,7 +520,7 @@ Page { privacy.currentIndex = setIndex } - console.log(JSON.stringify()) + // console.log(JSON.stringify()) worker.sendMessage({ "action": 'statuses/' + mdl.get(0).status_id + '/context', diff --git a/qml/pages/LoginPage.qml b/qml/pages/LoginPage.qml index d71b389..4df27d5 100644 --- a/qml/pages/LoginPage.qml +++ b/qml/pages/LoginPage.qml @@ -7,6 +7,7 @@ import "../lib/API.js" as Logic Page { + property bool debug: false // Python connections and signals, callable from QML side // This is not ideal but keeps the page from erroring out on redirect @@ -17,13 +18,13 @@ Page { importModule('server', function () {}); setHandler('finished', function(newvalue) { - console.debug(newvalue) + if(debug) console.debug(newvalue) }); startDownload(); } function startDownload() { call('server.downloader.serve', function() {}); - console.debug("called") + if (debug) console.debug("called") } } @@ -64,10 +65,10 @@ Page { Logic.api.registerApplication("Tooter", 'http://localhost:8000/index.html', // redirect uri, we will need this later on ["read", "write", "follow"], //scopes - "http://grave-design.com/harbour-tooter", //website on the login screen + "https://github.com/poetaster/harbour-tooter#readme", //website on the login screen function(data) { - console.log(data) + if (debug) console.log(data) var conf = JSON.parse(data) conf.instance = instance.text; conf.login = false; @@ -78,8 +79,8 @@ Page { conf['mastodon_client_redirect_uri'] = data['mastodon_client_redirect_uri']; delete Logic.conf;*/ Logic.conf = conf; - console.log(JSON.stringify(conf)) - console.log(JSON.stringify(Logic.conf)) + if(debug) console.log(JSON.stringify(conf)) + if(debug) console.log(JSON.stringify(Logic.conf)) // we got our application // our user to it! @@ -88,7 +89,7 @@ Page { "code", // oauth method ["read", "write", "follow"] //scopes ); - console.log(url) + if(debug) console.log(url) webView.url = url webView.visible = true } @@ -128,32 +129,27 @@ Page { } onRecvAsyncMessage: { - console.log('async changed: ' + url) - console.debug(message) + if(debug) console.log('async changed: ' + url) + if(debug) console.debug(message) switch (message) { case "embed:contentOrientationChanged": break case "webview:action": - if ( data.topic != lon ) { - //webview.runJavaScript("return latlon('" + lat + "','" + lon + "')"); - //if (debug) console.debug(data.topic) - //if (debug) console.debug(data.also) - //if (debug) console.debug(data.src) - } break } } visible: false //opacity: 0 - anchors { + anchors.fill: parent + /*{ top: parent.top left: parent.left right: parent.right bottom: parent.bottom - } + }*/ onLoadingChanged: { - console.log('loading changed: ' + url) + if(debug) console.log('loading changed: ' + url) if ( (url+"").substr(0, 38) === 'http://localhost:8000/index.html?code=' || (url+"").substr(0, 39) === 'https://localhost:8000/index.html?code=' @@ -165,7 +161,7 @@ Page { var authCode = vars["code"]; - console.log(authCode) + if(debug) console.log(authCode) Logic.api.getAccessTokenFromAuthCode( Logic.conf["client_id"], @@ -174,10 +170,10 @@ Page { authCode, function(data) { // AAAND DATA CONTAINS OUR TOKEN! - console.log(data) + if(debug) console.log(data) data = JSON.parse(data) - console.log(JSON.stringify(data)) - console.log(JSON.stringify(data.access_token)) + if(debug) console.log(JSON.stringify(data)) + if(debug) console.log(JSON.stringify(data.access_token)) Logic.conf["api_user_token"] = data.access_token Logic.conf["login"] = true; Logic.api.setConfig("api_user_token", Logic.conf["api_user_token"]) diff --git a/qml/pages/MainPage.qml b/qml/pages/MainPage.qml index 0ce3be1..c155e69 100644 --- a/qml/pages/MainPage.qml +++ b/qml/pages/MainPage.qml @@ -6,7 +6,7 @@ import "./components/" Page { id: mainPage - + property bool debug: false property bool isFirstPage: true property bool isTablet: true //Screen.sizeCategory >= Screen.Large @@ -24,7 +24,8 @@ Page { id: navigation isPortrait: !mainPage.isPortrait onSlideshowShow: { - console.log(vIndex) + if (debug) console.log(vIndex) + slideshow.positionViewAtIndex(vIndex, ListView.SnapToItem) } } @@ -74,6 +75,15 @@ Page { height: parent.itemHeight onOpenDrawer: isPortrait ? infoPanel.open = setDrawer : infoPanel.open = true } + MyList { + id: tlBookmarks + title: qsTr("Bookmarks") + type: "bookmarks" + mdl: Logic.modelTLbookmarks + width: isPortrait ? parent.itemWidth : parent.itemWidth - Theme.itemSizeLarge + height: parent.itemHeight + onOpenDrawer: isPortrait ? infoPanel.open = setDrawer : infoPanel.open = true + } Item { id: tlSearch @@ -84,7 +94,7 @@ Page { width: isPortrait ? parent.itemWidth : parent.itemWidth - Theme.itemSizeLarge height: parent.itemHeight onSearchChanged: { - console.log(search) + if (debug) console.log(search) loader.sourceComponent = loading if (search.charAt(0) === "@") { loader.sourceComponent = userListComponent @@ -114,7 +124,7 @@ Page { EnterKey.onClicked: { tlSearch.search = text.toLowerCase().trim() focus = false - console.log(text) + if (debug) console.log(text) } } } @@ -148,6 +158,18 @@ Page { delegate: VisualContainer Component.onCompleted: { view.type = "timelines/tag/"+tlSearch.search.substring(1) + var ids = [] + view.params = [] + view.params.push({name: 'limit', data: "20" }); + /* we push the ids via params which we remove in the WorkerScript + * see: MyList:loadData() and should move */ + if (mdl.count) { + for(var i = 0 ; i < mdl.count ; i++) { + ids.push(mdl.get(i).id) + //if (debug) console.log(model.get(i).id) + } + view.params.push({name: 'ids', data: ids }); + } view.loadData("append") } } @@ -219,8 +241,20 @@ Page { delegate: VisualContainer Component.onCompleted: { + var ids = [] + view3.params = [] + view3.params.push({name: 'limit', data: "20" }); + /* we push the ids via params which we remove in the WorkerScript + * see: MyList:loadData() and should move */ + if (mdl.count) { + for(var i = 0 ; i < mdl.count ; i++) { + ids.push(mdl.get(i).id) + //if (debug) console.log(model.get(i).id) + } + view3.params.push({name: 'ids', data: ids }); + } view3.type = "timelines/tag/"+tlSearch.search - view3.loadData("append") + view3.loadData("prepend") } } } @@ -270,17 +304,21 @@ Page { function onLinkActivated(href) { var test = href.split("/") - console.log(href) - console.log(JSON.stringify(test)) - console.log(JSON.stringify(test.length)) + debug = true + if (debug) { + console.log(href) + console.log(JSON.stringify(test)) + console.log(JSON.stringify(test.length)) + } if (test.length === 5 && (test[3] === "tags" || test[3] === "tag") ) { tlSearch.search = "#"+decodeURIComponent(test[4]) - slideshow.positionViewAtIndex(4, ListView.SnapToItem) + slideshow.positionViewAtIndex(5, ListView.SnapToItem) navigation.navigateTo('search') + if (debug) console.log("search tag") } else if (test.length === 4 && test[3][0] === "@" ) { tlSearch.search = decodeURIComponent("@"+test[3].substring(1)+"@"+test[2]) - slideshow.positionViewAtIndex(4, ListView.SnapToItem) + slideshow.positionViewAtIndex(5, ListView.SnapToItem) navigation.navigateTo('search') } else { @@ -289,6 +327,6 @@ Page { } Component.onCompleted: { - console.log("aaa") + //console.log("aaa") } } diff --git a/qml/pages/ProfilePage.qml b/qml/pages/ProfilePage.qml index efb5b21..96268da 100644 --- a/qml/pages/ProfilePage.qml +++ b/qml/pages/ProfilePage.qml @@ -29,12 +29,13 @@ Page { property bool muting: false property bool domain_blocking: false property date created_at + property bool debug: false WorkerScript { id: worker source: "../lib/Worker.js" onMessage: { - console.log(JSON.stringify(messageObject)) + if (debug) console.log(JSON.stringify(messageObject)) if(messageObject.action.indexOf("accounts/search") > -1 ){ user_id = messageObject.data.id followers_count = messageObject.data.followers_count @@ -54,7 +55,7 @@ Page { } if(messageObject.action === "accounts/relationships/"){ - console.log(JSON.stringify(messageObject)) + if (debug) console.log(JSON.stringify(messageObject)) following = messageObject.data.following requested = messageObject.data.requested followed_by = messageObject.data.followed_by @@ -190,9 +191,9 @@ Page { anchors.horizontalCenter: parent.horizontalCenter onLinkActivated: { var test = link.split("/") - console.log(link) - console.log(JSON.stringify(test)) - console.log(JSON.stringify(test.length)) + if (debug) console.log(link) + if (debug) console.log(JSON.stringify(test)) + if (debug) console.log(JSON.stringify(test.length)) if (test.length === 5 && (test[3] === "tags" || test[3] === "tag") ) { pageStack.pop(pageStack.find(function(page) { var check = page.isFirstPage === true; diff --git a/qml/pages/SettingsPage.qml b/qml/pages/SettingsPage.qml index ea9277b..4aa9354 100644 --- a/qml/pages/SettingsPage.qml +++ b/qml/pages/SettingsPage.qml @@ -153,6 +153,12 @@ Page { mastodon: "molan@fosstodon.org" mail: "" } + ListElement { + name: "poetaster" + desc: qsTr("Development") + mastodon: "postaster@mastodon.gamedev.place" + mail: "blueprint@poetaster.de" + } ListElement { name: "Miodrag Nikolić" diff --git a/qml/pages/components/MediaBlock.qml b/qml/pages/components/MediaBlock.qml index e3bb587..94cd21c 100644 --- a/qml/pages/components/MediaBlock.qml +++ b/qml/pages/components/MediaBlock.qml @@ -10,14 +10,18 @@ Item { property double wRatio : 16/9 property double hRatio : 9/16 + property bool debug: false width: width height: height Component.onCompleted: { + if(debug) console.log("MB: " + JSON.stringify(model.get(0))) + if (model && model.count && model.get(0).type === "video") { + //console.log("Mediablock") + //console.log(JSON.stringify(model.get(0).type)) while (model.count>1) { model.remove(model.count-1) } - //console.log(JSON.stringify(model.get(0))) } var count = 0 if (model && model.count) @@ -89,6 +93,8 @@ Item { type = model.get(0).type previewURL = model.get(0).preview_url mediaURL = model.get(0).url + url = model.get(0).url + if(debug) console.log( model.get(0).url ) height = Theme.itemSizeLarge return true } else { @@ -108,6 +114,8 @@ Item { type = model.get(1).type previewURL = model.get(1).preview_url mediaURL = model.get(1).url + url = model.get(0).url + if(debug) console.log( model.get(1).url ) height = Theme.itemSizeLarge return true } else { @@ -127,6 +135,7 @@ Item { type = model.get(2).type previewURL = model.get(2).preview_url mediaURL = model.get(2).url + url = model.get(0).url height = Theme.itemSizeLarge return true } else { @@ -146,6 +155,7 @@ Item { type = model.get(3).type previewURL = model.get(3).preview_url mediaURL = model.get(3).url + url = model.get(0).url height = Theme.itemSizeLarge return true } else { diff --git a/qml/pages/components/MediaFullScreen.qml b/qml/pages/components/MediaFullScreen.qml index f4adf7d..4b2525d 100644 --- a/qml/pages/components/MediaFullScreen.qml +++ b/qml/pages/components/MediaFullScreen.qml @@ -9,15 +9,26 @@ FullscreenContentPage { property string type: "" property string previewURL: "" property string mediaURL: "" + property string url: "" + property bool debug: false allowedOrientations: Orientation.All Component.onCompleted: function() { - console.log(type) - console.log(previewURL) - console.log(mediaURL) + if (debug) { + console.log(type) + console.log(previewURL) + console.log(mediaURL) + } if (type != 'gifv' && type != 'video') { imagePreview.source = mediaURL imageFlickable.visible = true + } else if( type == 'audio'){ + video.source = url + videoFlickable.visible = true + playerIcon.visible = true + playerProgress.visible = true + video.play() + hideTimer.start() } else { video.source = mediaURL video.fillMode = VideoOutput.PreserveAspectFit @@ -50,18 +61,18 @@ FullscreenContentPage { videoError.visible = true } onStatusChanged: { - console.log(status) + if(debug) console.log(status) switch (status) { case MediaPlayer.Loading: - console.log("loading") + if(debug) console.log("loading") return; case MediaPlayer.EndOfMedia: - console.log("EndOfMedia") + if (debug) console.log("EndOfMedia") return; } } onPlaybackStateChanged: { - console.log(playbackState) + if (debug) console.log(playbackState) switch (playbackState) { case MediaPlayer.PlayingState: playerIcon.icon.source = "image://theme/icon-m-pause" diff --git a/qml/pages/components/MediaItem.qml b/qml/pages/components/MediaItem.qml new file mode 100644 index 0000000..dc880e3 --- /dev/null +++ b/qml/pages/components/MediaItem.qml @@ -0,0 +1,323 @@ +import QtQuick 2.6 +import Sailfish.Silica 1.0 +import QtMultimedia 5.6 + + + +ListItem { + id: item + + property string url + property string mediaUrl + property string mimeType: 'audio/mp3' + property int length + + property bool _isAudio: mimeType.substring(0, 6) === "audio/" + property bool _isImage: mimeType.substring(0, 6) === "image/" + + function _toTime(s) + { + if (s < 0) + { + return "-"; + } + + s /= 1000; + var seconds = Math.floor(s) % 60; + s /= 60; + var minutes = Math.floor(s) % 60; + s /= 60; + var hours = Math.floor(s); + + if (seconds < 10) + { + seconds = "0" + seconds; + } + if (minutes < 10) + { + minutes = "0" + minutes; + } + + if (hours > 0) + { + return hours + ":" + minutes + ":" + seconds; + } + else + { + return minutes + ":" + seconds; + } + } + + /* Returns the filename of the given URL. + */ + function _urlFilename(url) { + var idx = url.lastIndexOf("="); + if (idx !== -1) { + return url.substring(idx + 1); + } + + idx = url.lastIndexOf("/"); + if (idx === url.length - 1) { + idx = url.substring(0, idx).lastIndexOf("/"); + } + + if (idx !== -1) { + return url.substring(idx + 1); + } + + return url; + } + + /* Returns the icon source for the given media. + */ + function _mediaIcon(url, type) { + if (type.substring(0, 6) === "image/") { + return url; + } else if (type.substring(0, 6) === "video/") { + return "image://theme/icon-l-play"; + } else { + return "image://theme/icon-m-other"; + } + } + + /* Returns a user-friendly media type name for the given MIME type. + */ + function _mediaTypeName(type) { + if (type.substring(0, 6) === "image/") { + return qsTr("Image"); + } else if (type.substring(0, 6) === "video/") { + return qsTr("Video"); + } else if (type === "application/pdf") { + return qsTr("PDF document"); + } else { + return type; + } + } + + onClicked: { + console.log('MediaItem') + console.log(url) + console.log(mediaUrl) + if (_isAudio) + { + if (audioProxy.playing) + { + audioProxy.pause(); + } + else + { + audioProxy.play(); + } + } + else if (_isImage) + { + var props = { + "url": item.url, + "name": _urlFilename(item.url) + } + pageStack.push(Qt.resolvedUrl("ImagePage.qml"), props); + } + else + { + Qt.openUrlExternally(item.url); + } + } + + QtObject { + id: audioProxy + + property bool _active: audioPlayer.source == source + property bool playing: _active ? audioPlayer.playing + : false + property bool paused: _active ? audioPlayer.paused + : false + property real duration: _active ? audioPlayer.duration + : -1 + property real position: _active ? audioPlayer.position + : 0 + + property string source: _isAudio ? item.url : "" + + property Timer _seeker: Timer { + interval: 50 + + onTriggered: { + if (audioProxy._active) + { + if (! audioPlayer.playing) + { + console.log("Stream is not ready. Deferring seek operation.") + _seeker.start(); + } + else + { + audioPlayer.seek(Math.max(0, database.audioBookmark(audioProxy.source) - 3000)); + } + } + } + } + + function play() + { + if (_active) + { + audioPlayer.play(); + } + else + { + // save bookmark before switching to another podcast + if (audioPlayer.playing) + { + database.setAudioBookmark(audioPlayer.source, + audioPlayer.position); + } + + audioPlayer.stop(); + audioPlayer.source = source; + audioPlayer.play(); + _seeker.start(); + } + } + + function pause() + { + if (_active) + { + //database.setAudioBookmark(source, audioPlayer.position); + audioPlayer.pause(); + } + } + + function seek(value) + { + if (_active) audioPlayer.seek(value); + } + + onPositionChanged: { + if (_active) + { + if (! slider.down) + { + slider.value = position; + } + } + } + + onDurationChanged: { + if (_active) + { + slider.maximumValue = duration; + } + } + } + Audio { + id: audioPlayer + property bool playing: playbackState === Audio.PlayingState + property bool paused: playbackState === Audio.PausedState + autoLoad: false + autoPlay: false + } + Image { + id: mediaIcon + + anchors.left: parent.left + anchors.leftMargin: Theme.paddingLarge + anchors.rightMargin: Theme.paddingMedium + width: height + height: parent.height + asynchronous: true + smooth: true + fillMode: Image.PreserveAspectCrop + sourceSize.width: width * 2 + sourceSize.height: height * 2 + source: ! _isAudio ? _mediaIcon(item.url, item.mimeType) + : audioProxy.playing ? "image://theme/icon-l-pause" + : "image://theme/icon-l-play" + clip: true + + BusyIndicator { + running: parent.status === Image.Loading + anchors.centerIn: parent + size: BusyIndicatorSize.Medium + } + } + + Label { + id: mediaNameLabel + + anchors.left: mediaIcon.right + anchors.right: parent.right + anchors.leftMargin: Theme.paddingLarge + anchors.rightMargin: Theme.paddingLarge + truncationMode: TruncationMode.Fade + font.pixelSize: Theme.fontSizeSmall + color: Theme.primaryColor + text: _urlFilename(item.url) + } + Label { + id: label1 + anchors.top: mediaNameLabel.bottom + anchors.left: mediaNameLabel.left + font.pixelSize: Theme.fontSizeExtraSmall + color: Theme.secondaryColor + text: ! slider.visible ? _mediaTypeName(item.mimeType) + : audioProxy.playing ? _toTime(slider.sliderValue) + : _toTime(database.audioBookmark(audioProxy.source)) + + } + Label { + id: label2 + anchors.top: mediaNameLabel.bottom + anchors.right: parent.right + anchors.rightMargin: Theme.paddingLarge + font.pixelSize: Theme.fontSizeExtraSmall + color: Theme.secondaryColor + text: slider.visible ? _toTime(audioProxy.duration) + : item.length >= 0 ? Format.formatFileSize(item.length) + : "" + } + + Slider { + id: slider + + visible: _isAudio + enabled: audioProxy.playing || audioProxy.paused + + anchors.left: label1.right + anchors.right: label2.left + anchors.verticalCenter: label1.verticalCenter + + leftMargin: Theme.paddingSmall + rightMargin: Theme.paddingSmall + height: Theme.itemSizeSmall / 3 + + handleVisible: false + minimumValue: 0 + + onDownChanged: { + if (! down) + { + audioProxy.seek(sliderValue); + if (! audioProxy.playing) + { + audioProxy.play(); + } + } + } + + }//Slider + IconButton { + id: mediaDlBtn + icon.source: "image://theme/icon-m-cloud-download" + anchors { + right: parent.right + rightMargin: Theme.horizontalPageMargin + bottom: parent.bottom + bottomMargin: Theme.horizontalPageMargin + } + onClicked: { + var filename = url.split("/") + FileDownloader.downloadFile(url, filename[filename.length-1]) + } + } +} diff --git a/qml/pages/components/MyList.qml b/qml/pages/components/MyList.qml index 23ddd73..12df57b 100644 --- a/qml/pages/components/MyList.qml +++ b/qml/pages/components/MyList.qml @@ -7,6 +7,7 @@ import "." SilicaListView { id: myList + property bool debug: false property string type property string title property string description @@ -17,15 +18,21 @@ SilicaListView { property bool loadStarted: false property int scrollOffset property string action: "" + // should consider better names or + // using min_ & max_id + property string linkprev: "" + property string linknext: "" property variant vars property variant conf property bool notifier: false + property bool deduping: false + property variant uniqueIds: [] model: mdl signal notify (string what, int num) onNotify: { - console.log(what + " - " + num) + if(debug) console.log(what + " - " + num) } signal openDrawer (bool setDrawer) onOpenDrawer: { @@ -33,7 +40,7 @@ SilicaListView { } signal send (string notice) onSend: { - console.log("LIST send signal emitted with notice: " + notice) + if (debug) console.log("LIST send signal emitted with notice: " + notice) } header: PageHeader { @@ -75,7 +82,6 @@ SilicaListView { pageStack.push(Qt.resolvedUrl("../SettingsPage.qml"), {}) } } - MenuItem { text: qsTr("New Toot") visible: !profilePage @@ -115,7 +121,10 @@ SilicaListView { } onCountChanged: { - loadStarted = false + if (debug) console.log("count changed on: " + title) + //deDouble() + //loadStarted = false + /*contentY = scrollOffset console.log("CountChanged!")*/ } @@ -130,7 +139,7 @@ SilicaListView { anchors.bottomMargin: Theme.paddingLarge visible: false onClicked: { - loadData("append") + if (!loadStarted && !deduping) loadData("append") } } @@ -150,9 +159,9 @@ SilicaListView { openDrawer(contentY - scrollOffset > 0 ? false : true ) scrollOffset = contentY } - if(contentY+height > footerItem.y && !loadStarted && autoLoadMore) { - loadData("append") - loadStarted = true + if(contentY+height > footerItem.y && !deduping && !loadStarted && autoLoadMore) { + loadStarted = true + loadData("append") } } @@ -163,37 +172,192 @@ SilicaListView { source: "../../lib/Worker.js" onMessage: { if (messageObject.error){ - console.log(JSON.stringify(messageObject)) + if (debug) console.log(JSON.stringify(messageObject)) + } else { + if (debug) console.log(JSON.stringify(messageObject)) + // loadStarted = false } + if (messageObject.fireNotification && notifier){ Logic.notifier(messageObject.data) } + + // temporary debugging measure + if (messageObject.updatedAll){ + if (debug) console.log("Got em all.") + if (model.count > 20) deDouble() + loadStarted = false + } + + // the api is stupid + if (messageObject.LinkHeader) { + // ; rel=\"next\", + // ; rel=\"prev\"" + + var matches = /max_id=([0-9]+)/.exec(messageObject.LinkHeader); + var maxlink = matches[0].split("=")[1]; + var matches = /min_id=([0-9]+)/.exec(messageObject.LinkHeader); + var minlink = matches[0].split("=")[1]; + if (debug) console.log("maxlink: " + maxlink) + if (debug) console.log("minlink: " + minlink) + linkprev = maxlink + linknext = minlink + } } } Component.onCompleted: { loadData("prepend") + if (debug) console.log("MyList completed: " + title) } Timer { - triggeredOnStart: false; interval: 5*60*1000; running: true; repeat: true + triggeredOnStart: false; + interval: { + + /* + * Varied calls so that server isn't hit + * simultaenously ... this is hamfisted + */ + var listInterval = Math.floor(Math.random() * 60)*10*1000 + if( title === "Home" ) listInterval = 20*60*1000 + if( title === "Local" ) listInterval = 10*60*1000 + if( title === "Federated" ) listInterval = 30*60*1000 + if( title === "Bookmarks" ) listInterval = 40*60*1000 + if( title === "Notifications" ) listInterval = 12*60*1000 + + if(debug) console.log(title + ' interval: ' + listInterval) + + return listInterval + } + running: true; + repeat: true onTriggered: { - console.log(title + ' ' +Date().toString()) - loadData("prepend") + if(debug) console.log(title + ' ' + Date().toString()) + // let's avoid pre and appending at the same time! + if ( ! loadStarted && ! deduping ) loadData("prepend") } } + /* + * NOT actually doing deduping :) + * utility called on updates to model to remove remove Duplicates: + * the dupes are probably a result of improper syncing of the models + * this is temporary and can probaly be removed because of the + * loadData method passing in to the WorkerScript + */ + function deDouble(){ + + deduping = true + var ids = [] + var uniqueItems = [] + var i + var j + var seenIt = 0 + + if (debug) console.log(model.count) + + for(i = 0 ; i < model.count ; i++) { + ids.push(model.get(i).id) + uniqueItems = removeDuplicates(ids) + + } + //if (debug) console.log(ids) + if (debug) console.log(uniqueItems.length) + if (debug) console.log( "max-one?:" + model.get(model.count - 2).id ) + if (debug) console.log( "max:" + model.get(model.count - 1).id ) + + if ( uniqueItems.length < model.count) { + + // it seems that only the last one, is an issue + /*if (model.get(model.count - 1).id > model.get(model.count - 2).id){ + model.remove(model.count - 1,1) + }*/ + + if (debug) console.log(model.count) + for(j = 0; j <= uniqueItems.length - 1 ; j++) { + seenIt = 0 + for(i = 0 ; i < model.count - 1 ; i++) { + if (model.get(i).id === uniqueItems[j]){ + seenIt = seenIt+1 + if (seenIt > 1) { + if (debug) console.log(uniqueItems[j] + " - " + seenIt) + + // model.remove(i,1) // (model.get(i)) + seenIt = seenIt-1 + } + } + } + } + } + + deduping = false + } + + /* utility function because this version of qt doesn't support modern javascript + * + */ + function removeDuplicates(arr) { + var unique = []; + for(var i=0; i < arr.length; i++){ + if(unique.indexOf(arr[i]) === -1) { + unique.push(arr[i]); + } + } + return unique; + } + + + /* Principle load function, uses websocket's worker.js + * + */ + function loadData(mode) { + + if (debug) console.log('loadData called: ' + mode + " in " + title) + // since the worker adds Duplicates + // we pass in current ids in the model + // and skip those on insert append in the worker + for(var i = 0 ; i < model.count ; i++) { + uniqueIds.push(model.get(i).id) + //if (debug) console.log(model.get(i).id) + } + uniqueIds = removeDuplicates(uniqueIds) + var p = [] if (params.length) { for(var i = 0; i" + 'Audio file' + '' + font.pixelSize: Theme.fontSizeLarge + }*/ + + + MediaItem { + id: audioContent + visible: type == 'audio' + opacity: img.status === Image.Ready ? 0.0 : 1.0 Behavior on opacity { FadeAnimator {} } - source: "image://theme/icon-m-file-audio?" + mimeType: 'audio/mp3' + url: mediaURL + mediaUrl: mediaURL + //source: "image://theme/icon-m-file-audio?" anchors.centerIn: parent + /*MouseArea { + anchors.fill: parent + onClicked: { + pageStack.push(Qt.resolvedUrl("./MediaItem.qml"), { + "url": url, + "type": type, + "mimeType": type + }) + } + } */ } Rectangle { @@ -67,6 +93,7 @@ Item { MouseArea { anchors.fill: parent + visible: type != 'audio' onClicked: { pageStack.push(Qt.resolvedUrl("./MediaFullScreen.qml"), { "previewURL": previewURL, @@ -109,5 +136,19 @@ Item { onClicked: parent.visible = false } } + /*IconButton { + id: mediaDlBtn + icon.source: "image://theme/icon-m-cloud-download" + anchors { + right: parent.right + rightMargin: Theme.horizontalPageMargin + bottom: parent.bottom + bottomMargin: Theme.horizontalPageMargin + } + onClicked: { + var filename = url.split("/") + FileDownloader.downloadFile(url, filename[filename.length-1]) + } + }*/ } } diff --git a/qml/pages/components/NavigationPanel.qml b/qml/pages/components/NavigationPanel.qml index 9846baa..ffeefa0 100644 --- a/qml/pages/components/NavigationPanel.qml +++ b/qml/pages/components/NavigationPanel.qml @@ -38,7 +38,6 @@ SilicaGridView { active: false unread: false } - ListElement { icon: "image://theme/icon-m-website?" slug: "federated" @@ -47,6 +46,14 @@ SilicaGridView { unread: false } + ListElement { + icon: "../../images/icon-s-bookmark.svg?" + //icon: "image://theme/icon-s-bookmark" + slug: "bookmarks" + name: "Bookmarks" + active: false + unread: false + } ListElement { icon: "image://theme/icon-m-search?" slug: "search" diff --git a/qml/pages/components/VisualContainer.qml b/qml/pages/components/VisualContainer.qml index af62906..a5b6db3 100644 --- a/qml/pages/components/VisualContainer.qml +++ b/qml/pages/components/VisualContainer.qml @@ -6,6 +6,8 @@ import "../../lib/API.js" as Logic BackgroundItem { id: delegate + property bool debug:false + signal send (string notice) signal navigateTo(string link) @@ -195,9 +197,11 @@ BackgroundItem { } onLinkActivated: { var test = link.split("/") - console.log(link) - console.log(JSON.stringify(test)) - console.log(JSON.stringify(test.length)) + if (debug) { + console.log(link) + console.log(JSON.stringify(test)) + console.log(JSON.stringify(test.length)) + } if (test.length === 5 && (test[3] === "tags" || test[3] === "tag") ) { pageStack.pop(pageStack.find(function(page) { var check = page.isFirstPage === true; @@ -447,11 +451,11 @@ BackgroundItem { } onPressAndHold: { - console.log(JSON.stringify(mdl.get(index))) + if (debug) console.log(JSON.stringify(mdl.get(index))) mnu.open(delegate) } onDoubleClicked: { - console.log("double click") + if (debug) console.log("double click") } } diff --git a/rpm/harbour-tooterb.changes b/rpm/harbour-tooterb.changes index 4581a83..51ca28b 100644 --- a/rpm/harbour-tooterb.changes +++ b/rpm/harbour-tooterb.changes @@ -1,3 +1,48 @@ +* Thu Jan 5 2023 Mark Washeim 1.1.3 +- Add changes from gitlogs (++) Bump for tag release. +- Add conditional append all for search when no knownIds +- Add correction to linkprev for bookmarks (and follows, etc) + +* Wed Jan 4 2023 Mark Washeim 1.1.2 +- Add conditional append all for search when no knownIds Workers.js +- Add linkprev/next for bookmarks (and follows, etc) MyList +- getLink method in Mastodon.js HEAD requests for Link + +* Fri Dec 23 2022 Mark Washeim 1.1.1 +- This is an interim release that should not have been released + +* Fri Dec 2 2022 Mark Washeim 1.1.0 +- Added some more debug flags to stop spewing the console. +- Added self to credits. +- Added MediaItem display for audio and Integrated MediaItem into MediaBlock/MyMedia elements. +- Add additional; media element for audio. +- Merge pull request #16 from cintema/patch-2 +- Merge pull request #15 from cintema/patch-1 +- Update harbour-tooterb.spec +- Update LoginPage.qml +- Merge pull request #5 from eson57/patch-2 +- Update harbour-tooterb-sv.ts + +* Wed Nov 16 2022 Mark Washeim 1.0.9 +- Forgot to remove the yaml from spec. duh. +- Boost release. +- Update translations, partially for new bookmarks view. +- Remove yaml since it's just in the way. +- Added navigation elements and model for bookmarks. + +* Mon Nov 14 2022 Mark Washeim 1.0.8-3 +- Had neglected linguist include which is required for building on obs + +* Wed Nov 9 2022 Mark Washeim 1.0.8-2 +- Added minimal info to spec/yaml to include a release in chum. +- Merge pull request #100 from poetaster/master +- Merge pull request #99 from juanro49/master +- Fix reblog content view + +* Wed Nov 9 2022 Mark Washeim 1.0.8 +- Add python server for callbacks +- Add new WebView to better render callbacks + *Sun Jul 12 2020 molan 1.0.7-0 - Fix missing / wrong reblog and favourite counts in Retoots (issue #90) - Added full landscape support diff --git a/rpm/harbour-tooterb.spec b/rpm/harbour-tooterb.spec index d6c4e9b..93a27ea 100644 --- a/rpm/harbour-tooterb.spec +++ b/rpm/harbour-tooterb.spec @@ -13,16 +13,18 @@ Name: harbour-tooterb %{!?qtc_make:%define qtc_make make} %{?qtc_builddir:%define _builddir %qtc_builddir} Summary: Tooter β -Version: 1.0.7 -Release: 0 +Version: 1.1.3 +Release: 1 Group: Qt/Qt -License: LICENSE -URL: http://example.org/ +License: GPLv3 +URL: https://github.com/poetaster/harbour-tooter#readme Source0: %{name}-%{version}.tar.bz2 -Source100: harbour-tooterb.yaml Requires: sailfishsilica-qt5 >= 0.10.9 Requires: nemo-qml-plugin-configuration-qt5 Requires: nemo-qml-plugin-notifications-qt5 +Requires: pyotherside-qml-plugin-python3-qt5 + +BuildRequires: qt5-qttools-linguist BuildRequires: pkgconfig(sailfishapp) >= 1.0.2 BuildRequires: pkgconfig(Qt5Core) BuildRequires: pkgconfig(Qt5Qml) @@ -36,6 +38,19 @@ BuildRequires: desktop-file-utils %description Tooter Beta is a native client for Mastodon network instances. +%if "%{?vendor}" == "chum" +PackageName: Tooter Beta +Type: desktop-application +Categories: + - Network +PackagerName: Mark Washeim (poetaster) +Custom: + - Repo: https://github.com/molan-git/harbour-tooter + - PackagingRepo: https://github.com/poetaster/harbour-tooter +Icon: https://raw.githubusercontent.com/poetaster/harbour-tooter/master/icons/256x256/harbour-tooterb.png +Url: + - Bugtracker: https://github.com/poetaster/harbour-tooter/issues +%endif %prep %setup -q -n %{name}-%{version} diff --git a/rpm/harbour-tooterb.yaml b/rpm/harbour-tooterb.yaml deleted file mode 100644 index 078cba6..0000000 --- a/rpm/harbour-tooterb.yaml +++ /dev/null @@ -1,50 +0,0 @@ -Name: harbour-tooterb -Summary: Tooter β -Version: 1.0.7 -Release: 0 -# The contents of the Group field should be one of the groups listed here: -# https://github.com/mer-tools/spectacle/blob/master/data/GROUPS -Group: Qt/Qt -URL: http://example.org/ -License: LICENSE -# This must be generated before uploading a package to a remote build service. -# Usually this line does not need to be modified. -Sources: -- '%{name}-%{version}.tar.bz2' -Description: | - Tooter Beta is a native client for Mastodon network instances. -Configure: none -# The qtc5 builder inserts macros to allow QtCreator to have fine -# control over qmake/make execution -Builder: qtc5 - -# This section specifies build dependencies that are resolved using pkgconfig. -# This is the preferred way of specifying build dependencies for your package. -PkgConfigBR: - - sailfishapp >= 1.0.2 - - Qt5Core - - Qt5Qml - - Qt5Quick - - Qt5DBus - - Qt5Multimedia - #- nemonotifications-qt5 nemo-qml-plugin-notifications-qt5 - - nemo-qml-plugin-notifications-qt5-devel - - openssl - -# Build dependencies without a pkgconfig setup can be listed here -# PkgBR: -# - qt5-qtmultimedia-plugin-mediaservice-gstmediaplayer - -# Runtime dependencies which are not automatically detected -Requires: - - sailfishsilica-qt5 >= 0.10.9 - -# All installed files -Files: - - '%{_bindir}' - - '%{_datadir}/%{name}' - - '%{_datadir}/applications/%{name}.desktop' - - '%{_datadir}/icons/hicolor/*/apps/%{name}.png' - -# For more information about yaml and what's supported in Sailfish OS -# build system, please see https://wiki.merproject.org/wiki/Spectacle diff --git a/translations/harbour-tooterb-de.ts b/translations/harbour-tooterb-de.ts index ebe1c3c..607e9a4 100644 --- a/translations/harbour-tooterb-de.ts +++ b/translations/harbour-tooterb-de.ts @@ -149,6 +149,10 @@ New Toot Neuer Toot + + Bookmarks + Lesezeichen + MediaFullScreen @@ -157,6 +161,21 @@ Ladefehler + + MediaItem + + Image + + + + Video + + + + PDF document + + + MiniStatus @@ -356,6 +375,10 @@ to help with app translation to your language. um bei den Übersetzungen mitzuhelfen. + + Development + + VisualContainer diff --git a/translations/harbour-tooterb-el.ts b/translations/harbour-tooterb-el.ts index a4a7b3b..c397e1d 100644 --- a/translations/harbour-tooterb-el.ts +++ b/translations/harbour-tooterb-el.ts @@ -149,6 +149,10 @@ New Toot Νέος + + Bookmarks + + MediaFullScreen @@ -157,6 +161,21 @@ + + MediaItem + + Image + + + + Video + + + + PDF document + + + MiniStatus @@ -356,6 +375,10 @@ to help with app translation to your language. για να βοηθήσετε την μετάφραση της εφαρμογής στην γλώσσα σας. + + Development + + VisualContainer diff --git a/translations/harbour-tooterb-es.ts b/translations/harbour-tooterb-es.ts index 6641309..9d96657 100644 --- a/translations/harbour-tooterb-es.ts +++ b/translations/harbour-tooterb-es.ts @@ -149,6 +149,10 @@ New Toot Nuevo toot + + Bookmarks + Marcador + MediaFullScreen @@ -157,6 +161,21 @@ Error al cargar + + MediaItem + + Image + + + + Video + + + + PDF document + + + MiniStatus @@ -356,6 +375,10 @@ to help with app translation to your language. para ayudar con traducciones. + + Development + + VisualContainer diff --git a/translations/harbour-tooterb-fr.ts b/translations/harbour-tooterb-fr.ts index 5657178..8e4ad82 100644 --- a/translations/harbour-tooterb-fr.ts +++ b/translations/harbour-tooterb-fr.ts @@ -149,6 +149,10 @@ New Toot Nouveau pouet + + Bookmarks + Marque-page + MediaFullScreen @@ -157,6 +161,21 @@ Erreur au chargement + + MediaItem + + Image + + + + Video + + + + PDF document + + + MiniStatus @@ -356,6 +375,10 @@ to help with app translation to your language. pour aider à traduire cette application. + + Development + + VisualContainer diff --git a/translations/harbour-tooterb-it.ts b/translations/harbour-tooterb-it.ts index 9b7dfe8..30ac17f 100644 --- a/translations/harbour-tooterb-it.ts +++ b/translations/harbour-tooterb-it.ts @@ -149,6 +149,10 @@ New Toot Nuovo Toot + + Bookmarks + Segnalibro + MediaFullScreen @@ -157,6 +161,21 @@ Errore durante caricamento + + MediaItem + + Image + + + + Video + + + + PDF document + + + MiniStatus @@ -356,6 +375,10 @@ to help with app translation to your language. per aiutare nella traduzione dell'app. + + Development + + VisualContainer diff --git a/translations/harbour-tooterb-nl.ts b/translations/harbour-tooterb-nl.ts index e0bf1d1..a5b6f76 100644 --- a/translations/harbour-tooterb-nl.ts +++ b/translations/harbour-tooterb-nl.ts @@ -149,6 +149,10 @@ New Toot Nieuwe Toot + + Bookmarks + Bookmarken + MediaFullScreen @@ -157,6 +161,21 @@ Laadfout + + MediaItem + + Image + + + + Video + + + + PDF document + + + MiniStatus @@ -356,6 +375,10 @@ to help with app translation to your language. om deze app te helpen vertalen in jouw taal. + + Development + + VisualContainer diff --git a/translations/harbour-tooterb-nl_BE.ts b/translations/harbour-tooterb-nl_BE.ts index 0089850..7792bf9 100644 --- a/translations/harbour-tooterb-nl_BE.ts +++ b/translations/harbour-tooterb-nl_BE.ts @@ -149,6 +149,10 @@ New Toot Nieuwen toot + + Bookmarks + + MediaFullScreen @@ -157,6 +161,21 @@ + + MediaItem + + Image + + + + Video + + + + PDF document + + + MiniStatus @@ -356,6 +375,10 @@ to help with app translation to your language. voor te helpen met dezen app in uw taal te vertalen. + + Development + + VisualContainer diff --git a/translations/harbour-tooterb-oc.ts b/translations/harbour-tooterb-oc.ts index 81fb159..ee636dc 100644 --- a/translations/harbour-tooterb-oc.ts +++ b/translations/harbour-tooterb-oc.ts @@ -149,6 +149,10 @@ New Toot Nòu Tut + + Bookmarks + + MediaFullScreen @@ -157,6 +161,21 @@ + + MediaItem + + Image + + + + Video + + + + PDF document + + + MiniStatus @@ -356,6 +375,10 @@ to help with app translation to your language. per ajudar a traduire l’aplicacion dins vòstra lenga. + + Development + + VisualContainer diff --git a/translations/harbour-tooterb-pl.ts b/translations/harbour-tooterb-pl.ts index 8c1140c..c1dda8f 100644 --- a/translations/harbour-tooterb-pl.ts +++ b/translations/harbour-tooterb-pl.ts @@ -149,6 +149,10 @@ New Toot Nowy wpis + + Bookmarks + + MediaFullScreen @@ -157,6 +161,21 @@ + + MediaItem + + Image + + + + Video + + + + PDF document + + + MiniStatus @@ -356,6 +375,10 @@ to help with app translation to your language. + + Development + + VisualContainer diff --git a/translations/harbour-tooterb-ru.ts b/translations/harbour-tooterb-ru.ts index 98a54ca..c082582 100644 --- a/translations/harbour-tooterb-ru.ts +++ b/translations/harbour-tooterb-ru.ts @@ -149,6 +149,10 @@ New Toot Новый + + Bookmarks + + MediaFullScreen @@ -157,6 +161,21 @@ Ошибка при загрузке + + MediaItem + + Image + + + + Video + + + + PDF document + + + MiniStatus @@ -356,6 +375,10 @@ to help with app translation to your language. чтобы помочь с переводом приложения на ваш язык. + + Development + + VisualContainer diff --git a/translations/harbour-tooterb-sr.ts b/translations/harbour-tooterb-sr.ts index 11298c2..39bd8b0 100644 --- a/translations/harbour-tooterb-sr.ts +++ b/translations/harbour-tooterb-sr.ts @@ -149,6 +149,10 @@ New Toot Novi toot + + Bookmarks + + MediaFullScreen @@ -157,6 +161,21 @@ + + MediaItem + + Image + + + + Video + + + + PDF document + + + MiniStatus @@ -356,6 +375,10 @@ to help with app translation to your language. и помозите у преводу апликације на други језик. + + Development + + VisualContainer diff --git a/translations/harbour-tooterb-sv.ts b/translations/harbour-tooterb-sv.ts index 53b7f6e..2f28c5b 100644 --- a/translations/harbour-tooterb-sv.ts +++ b/translations/harbour-tooterb-sv.ts @@ -25,50 +25,50 @@ Copy Link to Clipboard Use the translation of "Copy Link" for a shorter PullDownMenu label - + Kopiera länk till urklipp Write your warning here placeholderText in Toot content warning panel - + Skriv din varningstext här What's on your mind? placeholderText in Toot text panel - + Vad tänker du på? Public - + Allmän Unlisted - + Olistad Followers-only - + Endast följare Direct - + Direkt Toot sent! - + Toot skickad! Reply "Reply" will show the Toot text entry Panel. "Hide Reply" closes it. Alternative: Use "Close Reply" - + Svara Hide Reply - + Dölj svar Open in Browser - + Öppna i webbläsaren @@ -104,19 +104,19 @@ Instance - + Instans Enter a valid Mastodon instance URL - Fyll i URL till Mastodoninstans + Ange en giltig URL till Mastodoninstans Mastodon is a free, open-source social network. A decentralized alternative to commercial platforms, it avoids the risks of a single company monopolizing your communication. Pick a server that you trust — whichever you choose, you can interact with everyone else. Anyone can run their own Mastodon instance and participate in the social network seamlessly. - Mastodon är ett fritt och öppet socialt nätverk byggt på öppen källkod. Ett decentraliserat alternativ till kommersiella plattformar, vilket undviker att ett ensamt företag monopoliserar din kommunikation. Välj en server du litar på --- beroende på vilken du väljer, kan du interagera med alla andra. Vem som helst kan köra deras egen Mastodoninstans och delta i nätverket. Även du! + Mastodon är ett fritt socialt nätverk byggt på öppen källkod. Ett decentraliserat alternativ till kommersiella plattformar. Det undviker riskerna med att ett enda företag monopoliserar din kommunikation. Välj en server som du litar på, oavsett vad du väljer kan du interagera med alla andra. Vem som helst kan köra sin egen Mastodon-instans och delta i det sociala nätverket sömlöst. Reload - Ladda mer + Läs in igen @@ -149,12 +149,31 @@ New Toot Ny toot + + Bookmarks + Bokmärken + MediaFullScreen Error loading - + Fel vid inläsning + + + + MediaItem + + Image + Bild + + + Video + Video + + + PDF document + PDF-dokument @@ -184,15 +203,15 @@ Reload - Ladda mer + Läs in igen Open in Browser - + Öppna i webbläsaren Nothing found - + Inget hittades @@ -203,11 +222,11 @@ Follows you - + Följer dig Group - + Grupp @@ -215,7 +234,7 @@ About If there's no good translation for "About", use "Details" (in details about profile). - + Om Followers @@ -230,11 +249,11 @@ Statuses Will show as: "115 Statuses" - Statusar + Status Mention - + Omnämnande Unfollow @@ -244,7 +263,7 @@ Requested Is a button. Keep it as short as possible. - + Efterfrågad Follow @@ -254,7 +273,7 @@ Unmute Is a button. Keep it as short as possible. - Avtysta + Frigör Mute @@ -280,15 +299,15 @@ Options - + Alternativ Load Images in Toots - Ladda bilder i toots + Läs in bilder i tootar Disable this option if you want to preserve your data connection - Inaktivera det här alternativet om du vill behålla din dataanslutning + Inaktivera det här alternativet om du vill bevara din dataanslutning Account @@ -296,7 +315,7 @@ Remove Account - Radera konto + Ta bort konto Add Account @@ -304,11 +323,11 @@ Deauthorize this app from using your account and remove account data from phone - Avauktorisera denna app och radera ditt konto + Avauktorisera denna app och ta bort din kontodata från telefonen Authorize this app to access your Mastodon account - Godkänn denna app att använda ditt Mastodon-konto på dina vägnar + Auktorisera denna app att använda ditt Mastodon-konto Translate @@ -325,27 +344,27 @@ Visual identity - + Visuell identitet Development and translations - + Utveckling och översättningar Occitan & French translation - + Occitan & Fransk översättning Chinese translation - + Kinesisk översättning Dutch translation - + Nederländsk översättning Spanish translation - + Spansk översättning Use @@ -354,7 +373,11 @@ to help with app translation to your language. - för att hjälpa med app-översättningar till ditt språk. + för att hjälpa till med app-översättning till ditt språk. + + + Development + Utveckling @@ -377,19 +400,19 @@ Mention - + Omnämnande Conversation - + Konversation Remove Bookmark - + Ta bort bokmärke Bookmark - + Bokmärk diff --git a/translations/harbour-tooterb-zh_CN.ts b/translations/harbour-tooterb-zh_CN.ts index 050c9fc..fa6d895 100644 --- a/translations/harbour-tooterb-zh_CN.ts +++ b/translations/harbour-tooterb-zh_CN.ts @@ -149,6 +149,10 @@ New Toot 新嘟嘟 + + Bookmarks + + MediaFullScreen @@ -157,6 +161,21 @@ 加载错误 + + MediaItem + + Image + + + + Video + + + + PDF document + + + MiniStatus @@ -356,6 +375,10 @@ to help with app translation to your language. 以帮助翻译软件为你使用的语言. + + Development + + VisualContainer diff --git a/translations/harbour-tooterb.ts b/translations/harbour-tooterb.ts index 49f0835..42f8869 100644 --- a/translations/harbour-tooterb.ts +++ b/translations/harbour-tooterb.ts @@ -149,6 +149,10 @@ New Toot New Toot + + Bookmarks + + MediaFullScreen @@ -157,6 +161,21 @@ Error loading + + MediaItem + + Image + + + + Video + + + + PDF document + + + MiniStatus @@ -356,6 +375,10 @@ to help with app translation to your language. to help with app translation to your language. + + Development + + VisualContainer