diff --git a/android/app/capacitor.build.gradle b/android/app/capacitor.build.gradle index a035cf07..c12243cc 100644 --- a/android/app/capacitor.build.gradle +++ b/android/app/capacitor.build.gradle @@ -9,6 +9,7 @@ android { apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle" dependencies { + implementation project(':byteowls-capacitor-filesharer') implementation project(':capacitor-app') implementation project(':capacitor-browser') implementation project(':capacitor-clipboard') diff --git a/android/app/src/main/assets/capacitor.plugins.json b/android/app/src/main/assets/capacitor.plugins.json index 91ba9d08..a2f6b93a 100644 --- a/android/app/src/main/assets/capacitor.plugins.json +++ b/android/app/src/main/assets/capacitor.plugins.json @@ -1,4 +1,8 @@ [ + { + "pkg": "@byteowls/capacitor-filesharer", + "classpath": "com.byteowls.capacitor.filesharer.FileSharerPlugin" + }, { "pkg": "@capacitor/app", "classpath": "com.capacitorjs.plugins.app.AppPlugin" diff --git a/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt b/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt index 94698d15..339954ee 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt @@ -116,6 +116,7 @@ class MainActivity : BridgeActivity() { override fun onSaveInstanceState(outState: Bundle) { storageHelper.onSaveInstanceState(outState) super.onSaveInstanceState(outState) + outState.clear() } override fun onRestoreInstanceState(savedInstanceState: Bundle) { diff --git a/android/capacitor.settings.gradle b/android/capacitor.settings.gradle index 4d93d79d..e38371ae 100644 --- a/android/capacitor.settings.gradle +++ b/android/capacitor.settings.gradle @@ -2,6 +2,9 @@ include ':capacitor-android' project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor') +include ':byteowls-capacitor-filesharer' +project(':byteowls-capacitor-filesharer').projectDir = new File('../node_modules/@byteowls/capacitor-filesharer/android') + include ':capacitor-app' project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android') diff --git a/components/stats/YearInReview.vue b/components/stats/YearInReview.vue new file mode 100644 index 00000000..4e04ec07 --- /dev/null +++ b/components/stats/YearInReview.vue @@ -0,0 +1,283 @@ + + + \ No newline at end of file diff --git a/components/stats/YearInReviewBanner.vue b/components/stats/YearInReviewBanner.vue new file mode 100644 index 00000000..dee1e155 --- /dev/null +++ b/components/stats/YearInReviewBanner.vue @@ -0,0 +1,134 @@ + + + \ No newline at end of file diff --git a/components/stats/YearInReviewServer.vue b/components/stats/YearInReviewServer.vue new file mode 100644 index 00000000..e6d443d0 --- /dev/null +++ b/components/stats/YearInReviewServer.vue @@ -0,0 +1,262 @@ + + + \ No newline at end of file diff --git a/components/stats/YearInReviewShort.vue b/components/stats/YearInReviewShort.vue new file mode 100644 index 00000000..ae77e987 --- /dev/null +++ b/components/stats/YearInReviewShort.vue @@ -0,0 +1,192 @@ + + + \ No newline at end of file diff --git a/ios/App/Podfile b/ios/App/Podfile index 531fb33f..b29cd4cb 100644 --- a/ios/App/Podfile +++ b/ios/App/Podfile @@ -11,6 +11,7 @@ install! 'cocoapods', :disable_input_output_paths => true def capacitor_pods pod 'Capacitor', :path => '../../node_modules/@capacitor/ios' pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios' + pod 'ByteowlsCapacitorFilesharer', :path => '../../node_modules/@byteowls/capacitor-filesharer' pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app' pod 'CapacitorBrowser', :path => '../../node_modules/@capacitor/browser' pod 'CapacitorClipboard', :path => '../../node_modules/@capacitor/clipboard' diff --git a/package-lock.json b/package-lock.json index 953ab15d..62dbdb29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "audiobookshelf-app", "version": "0.9.70-beta", "dependencies": { + "@byteowls/capacitor-filesharer": "^5.0.0", "@capacitor/android": "^5.0.0", "@capacitor/app": "^5.0.6", "@capacitor/browser": "^5.1.0", @@ -1939,6 +1940,17 @@ "node": ">=6.9.0" } }, + "node_modules/@byteowls/capacitor-filesharer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@byteowls/capacitor-filesharer/-/capacitor-filesharer-5.0.0.tgz", + "integrity": "sha512-LtIMd8Ge94Kj9BQWF+A646drHAkRVC6ulTPZ1InkQtNH4VIy3WfYilN20VZM5KkOvrQ1lslXFIJwquwKptLgmw==", + "dependencies": { + "file-saver": "2.0.5" + }, + "peerDependencies": { + "@capacitor/core": ">=5" + } + }, "node_modules/@capacitor/android": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-5.4.0.tgz", @@ -9195,6 +9207,11 @@ "node": ">=8.9.0" } }, + "node_modules/file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" + }, "node_modules/file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -21078,6 +21095,14 @@ "to-fast-properties": "^2.0.0" } }, + "@byteowls/capacitor-filesharer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@byteowls/capacitor-filesharer/-/capacitor-filesharer-5.0.0.tgz", + "integrity": "sha512-LtIMd8Ge94Kj9BQWF+A646drHAkRVC6ulTPZ1InkQtNH4VIy3WfYilN20VZM5KkOvrQ1lslXFIJwquwKptLgmw==", + "requires": { + "file-saver": "2.0.5" + } + }, "@capacitor/android": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-5.4.0.tgz", @@ -26353,6 +26378,11 @@ } } }, + "file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" + }, "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -34083,4 +34113,4 @@ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" } } -} \ No newline at end of file +} diff --git a/package.json b/package.json index 69ed6623..63387bc5 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "ionic:serve": "npm run start" }, "dependencies": { + "@byteowls/capacitor-filesharer": "^5.0.0", "@capacitor/android": "^5.0.0", "@capacitor/app": "^5.0.6", "@capacitor/browser": "^5.1.0", @@ -47,4 +48,4 @@ "postcss": "^8.3.5", "tailwindcss": "^3.3.2" } -} \ No newline at end of file +} diff --git a/pages/stats.vue b/pages/stats.vue index e9ff08dd..5c704b0b 100644 --- a/pages/stats.vue +++ b/pages/stats.vue @@ -1,5 +1,8 @@ + + + @@ -58,7 +64,8 @@ export default { data() { return { listeningStats: null, - windowWidth: 0 + windowWidth: 0, + showYearInReviewBanner: false } }, watch: { @@ -103,7 +110,12 @@ export default { console.error('Failed to load listening sesions', err) return [] }) - console.log('Loaded user listening data', this.listeningStats) + + let month = new Date().getMonth() + // January and December show year in review banner + if (month === 11 || month === 0) { + this.showYearInReviewBanner = true + } } }, mounted() { diff --git a/plugins/init.client.js b/plugins/init.client.js index 09c9b34c..14ce222c 100644 --- a/plugins/init.client.js +++ b/plugins/init.client.js @@ -94,26 +94,31 @@ Vue.prototype.$elapsedPretty = (seconds, useFullNames = false) => { return `${hours} ${useFullNames ? `hour${hours === 1 ? '' : 's'}` : 'hr'} ${minutes} ${useFullNames ? `minute${minutes === 1 ? '' : 's'}` : 'min'}` } -Vue.prototype.$elapsedPrettyExtended = (seconds, useDays = true) => { +Vue.prototype.$elapsedPrettyExtended = (seconds, useDays = true, showSeconds = true) => { if (isNaN(seconds) || seconds === null) return '' seconds = Math.round(seconds) - var minutes = Math.floor(seconds / 60) + let minutes = Math.floor(seconds / 60) seconds -= minutes * 60 - var hours = Math.floor(minutes / 60) + let hours = Math.floor(minutes / 60) minutes -= hours * 60 - var days = 0 + let days = 0 if (useDays || Math.floor(hours / 24) >= 100) { days = Math.floor(hours / 24) hours -= days * 24 } - var strs = [] + // If not showing seconds then round minutes up + if (minutes && seconds && !showSeconds) { + if (seconds >= 30) minutes++ + } + + const strs = [] if (days) strs.push(`${days}d`) if (hours) strs.push(`${hours}h`) if (minutes) strs.push(`${minutes}m`) - if (seconds) strs.push(`${seconds}s`) + if (seconds && showSeconds) strs.push(`${seconds}s`) return strs.join(' ') }