├── .github
└── ISSUE_TEMPLATE
│ └── bug_report.md
├── .gitignore
├── LICENSE
├── PRIVACY.md
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── caydey
│ │ └── ffshare
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-playstore.png
│ ├── java
│ │ └── com
│ │ │ └── caydey
│ │ │ └── ffshare
│ │ │ ├── App.kt
│ │ │ ├── CacheCleanUpReceiver.kt
│ │ │ ├── HandleMediaActivity.kt
│ │ │ ├── LogItemDialog.kt
│ │ │ ├── LogItemsAdapter.kt
│ │ │ ├── LogsActivity.kt
│ │ │ ├── MainActivity.kt
│ │ │ ├── PreferencesActivity.kt
│ │ │ ├── PreferencesFragment.kt
│ │ │ ├── SettingsVersionUpdater.kt
│ │ │ ├── extensions
│ │ │ ├── Compat.kt
│ │ │ └── Context.kt
│ │ │ └── utils
│ │ │ ├── ExifTools.kt
│ │ │ ├── FFmpegParamMaker.kt
│ │ │ ├── MediaCompressor.kt
│ │ │ ├── Settings.kt
│ │ │ ├── Utils.kt
│ │ │ └── logs
│ │ │ ├── Log.kt
│ │ │ └── LogsDbHelper.kt
│ └── res
│ │ ├── drawable
│ │ ├── ic_launcher_background.xml
│ │ └── ic_launcher_foreground.xml
│ │ ├── layout
│ │ ├── activity_handle_media.xml
│ │ ├── activity_logs.xml
│ │ ├── activity_main.xml
│ │ ├── activity_preferences.xml
│ │ ├── log_item_dialog.xml
│ │ └── log_item_view.xml
│ │ ├── menu
│ │ ├── menu_logs.xml
│ │ └── menu_main.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── navigation
│ │ └── nav_graph.xml
│ │ ├── values-es
│ │ └── strings.xml
│ │ ├── values-fr
│ │ ├── arrays.xml
│ │ └── strings.xml
│ │ ├── values-gl
│ │ └── strings.xml
│ │ ├── values-land
│ │ └── dimens.xml
│ │ ├── values-night
│ │ └── themes.xml
│ │ ├── values-tr
│ │ └── strings.xml
│ │ ├── values-w1240dp
│ │ └── dimens.xml
│ │ ├── values-w600dp
│ │ └── dimens.xml
│ │ ├── values-zh-rCN
│ │ ├── arrays.xml
│ │ └── strings.xml
│ │ ├── values-zh-rTW
│ │ └── strings.xml
│ │ ├── values
│ │ ├── arrays.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ │ └── xml
│ │ ├── filepaths.xml
│ │ └── preferences.xml
│ └── test
│ └── java
│ └── com
│ └── caydey
│ └── ffshare
│ └── ExampleUnitTest.kt
├── artwork
├── icon_background.svg
└── icon_foreground.svg
├── build.gradle
├── f-droid
└── com.caydey.ffshare.yml
├── fastlane
└── metadata
│ └── android
│ ├── en-US
│ ├── changelogs
│ │ ├── 10.txt
│ │ ├── 11.txt
│ │ ├── 12.txt
│ │ ├── 13.txt
│ │ ├── 14.txt
│ │ ├── 15.txt
│ │ ├── 16.txt
│ │ ├── 18.txt
│ │ ├── 19.txt
│ │ ├── 2.txt
│ │ ├── 20.txt
│ │ ├── 21.txt
│ │ ├── 22.txt
│ │ ├── 3.txt
│ │ ├── 4.txt
│ │ ├── 5.txt
│ │ ├── 6.txt
│ │ ├── 7.txt
│ │ ├── 8.txt
│ │ └── 9.txt
│ ├── full_description.txt
│ ├── images
│ │ ├── icon.png
│ │ └── phoneScreenshots
│ │ │ ├── 1.png
│ │ │ ├── 2.png
│ │ │ ├── 3.png
│ │ │ └── 4.png
│ ├── short_description.txt
│ ├── title.txt
│ └── video.txt
│ ├── fr-FR
│ ├── full_description.txt
│ ├── short_description.txt
│ └── title.txt
│ └── tr-TR
│ ├── full_description.txt
│ ├── images
│ ├── icon.png
│ └── phoneScreenshots
│ │ ├── 1.png
│ │ ├── 2.png
│ │ ├── 3.png
│ │ └── 4.png
│ ├── short_description.txt
│ ├── title.txt
│ └── video.txt
├── generate_test_files.sh
├── github_build_release.sh
├── google_play
└── feature_graphic.png
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Report a bug encountered with app
4 | title: ''
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 |
12 | **Settings applied**
13 | Does this happen on a clean install of the app or only when specific settings are changed
14 |
15 | **App Logs**
16 | Enable logs and provide a copy if it
17 |
18 | **File used**
19 | Uploading the file to help replicate the bug is very helpful however if it is not possible, run the following command on the file `ffprobe -v quiet -print_format json -show_format -show_streams FILE` and include its output
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea
5 |
6 | .DS_Store
7 | /app/full/release
8 | /build
9 | /captures
10 | .externalNativeBuild
11 | .cxx
12 | local.properties
13 |
14 | *.apk
15 | /repo
16 | /stats
17 | /app/release
18 |
19 | /github_releases
20 | /test_files
--------------------------------------------------------------------------------
/PRIVACY.md:
--------------------------------------------------------------------------------
1 | # FFShare Privacy Policy
2 | This is an open source Android application developed by Caydey. The source code is available on GitHub under the GNU General Public License v3.0
3 |
4 | # Data collected
5 | This app does not collect any personal information
6 |
7 | # Contact
8 | If you have any questions regarding this privacy policy, you can contact the developer at ffshare-caydey@protonmail.com
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #
FFShare
2 |
3 | [
](https://f-droid.org/app/com.caydey.ffshare)
6 | [
](https://apps.obtainium.imranr.dev/redirect?r=obtainium://app/%7B%22id%22%3A%22com.caydey.ffshare%22%2C%22url%22%3A%22https%3A%2F%2Fgithub.com%2Fcaydey%2Fffshare%22%2C%22author%22%3A%22caydey%22%2C%22name%22%3A%22FFShare%22%2C%22preferredApkIndex%22%3A1%2C%22additionalSettings%22%3A%22%7B%5C%22includePrereleases%5C%22%3Afalse%2C%5C%22fallbackToOlderReleases%5C%22%3Atrue%2C%5C%22filterReleaseTitlesByRegEx%5C%22%3A%5C%22%5C%22%2C%5C%22filterReleaseNotesByRegEx%5C%22%3A%5C%22%5C%22%2C%5C%22verifyLatestTag%5C%22%3Afalse%2C%5C%22dontSortReleasesList%5C%22%3Afalse%2C%5C%22useLatestAssetDateAsReleaseDate%5C%22%3Afalse%2C%5C%22releaseTitleAsVersion%5C%22%3Afalse%2C%5C%22trackOnly%5C%22%3Afalse%2C%5C%22versionExtractionRegEx%5C%22%3A%5C%22%5C%22%2C%5C%22matchGroupToUse%5C%22%3A%5C%22%5C%22%2C%5C%22versionDetection%5C%22%3Atrue%2C%5C%22releaseDateAsVersion%5C%22%3Afalse%2C%5C%22useVersionCodeAsOSVersion%5C%22%3Afalse%2C%5C%22apkFilterRegEx%5C%22%3A%5C%22%5C%22%2C%5C%22invertAPKFilter%5C%22%3Afalse%2C%5C%22autoApkFilterByArch%5C%22%3Atrue%2C%5C%22appName%5C%22%3A%5C%22%5C%22%2C%5C%22shizukuPretendToBeGooglePlay%5C%22%3Afalse%2C%5C%22allowInsecure%5C%22%3Afalse%2C%5C%22exemptFromBackgroundUpdates%5C%22%3Afalse%2C%5C%22skipUpdateNotifications%5C%22%3Afalse%2C%5C%22about%5C%22%3A%5C%22%5C%22%2C%5C%22refreshBeforeDownload%5C%22%3Afalse%7D%22%2C%22overrideSource%22%3A%22GitHub%22%7D)
9 |
10 | [](https://github.com/caydey/ffshare/releases/latest)
11 | [](https://github.com/caydey/ffshare/releases/latest)
12 | [](https://github.com/caydey/ffshare/blob/master/LICENSE)
13 |
14 | An android app to compress image, video and audio files through ffmpeg before sharing them
15 |
16 | ## Images
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | ## Used Libraries
26 |
27 | - [FFmpegKit](https://github.com/arthenica/ffmpeg-kit)
28 | - [Timber](https://github.com/JakeWharton/timber)
29 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | android {
7 | compileSdk 34
8 |
9 | defaultConfig {
10 | applicationId "com.caydey.ffshare"
11 | minSdk 26
12 | targetSdk 34
13 | versionCode 22
14 | versionName "1.3.3"
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | }
18 | signingConfigs {
19 | release {
20 | // environment variables from ~/.gradle/gradle.properties
21 | storeFile file(FFSHARE_RELEASE_STORE_FILE)
22 | storePassword FFSHARE_RELEASE_STORE_PASSWORD
23 | keyAlias FFSHARE_RELEASE_KEY_ALIAS
24 | keyPassword FFSHARE_RELEASE_KEY_PASSWORD
25 | }
26 | }
27 |
28 | splits {
29 | // Configures multiple APKs based on ABI.
30 | abi {
31 | // Enables building multiple APKs per ABI.
32 | enable true
33 |
34 | // Resets the list of ABIs for Gradle to create APKs for to none.
35 | reset()
36 |
37 | //noinspection ChromeOsAbiSupport
38 | include "armeabi-v7a", "arm64-v8a"
39 |
40 | // Create apk with merged ABI libraries
41 | universalApk true
42 | }
43 | }
44 |
45 | flavorDimensions += 'version'
46 | productFlavors {
47 | full {
48 | dimension 'version'
49 | }
50 | video {
51 | dimension 'version'
52 | }
53 | }
54 |
55 |
56 | buildTypes {
57 | release {
58 | ndk {
59 | //noinspection ChromeOsAbiSupport
60 | abiFilters "armeabi-v7a", "arm64-v8a"
61 | }
62 | minifyEnabled true
63 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
64 | signingConfig signingConfigs.release
65 | }
66 | debug {
67 | ndk {
68 | abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
69 | }
70 | minifyEnabled false
71 | }
72 |
73 | }
74 |
75 | // applicationVariants.all { variant ->
76 | // def version = variant.name
77 | // def name = variant.buildType
78 | // def flavor = variant.flavorName
79 | // def apkName = "${name}_${flavor}_${version}.apk"
80 | // variant.outputs.all { output -> {
81 | // outputFileName = apkName
82 | // }}
83 | // }
84 | compileOptions {
85 | sourceCompatibility JavaVersion.VERSION_1_8
86 | targetCompatibility JavaVersion.VERSION_1_8
87 | }
88 | kotlinOptions {
89 | jvmTarget = '1.8'
90 | }
91 | buildFeatures {
92 | viewBinding true
93 | buildConfig true
94 | }
95 | namespace 'com.caydey.ffshare'
96 | }
97 | dependencies {
98 | implementation 'androidx.core:core-ktx:1.8.0'
99 | implementation 'androidx.appcompat:appcompat:1.5.0'
100 | implementation 'com.google.android.material:material:1.6.1'
101 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
102 | implementation 'androidx.navigation:navigation-fragment-ktx:2.5.1'
103 | implementation 'androidx.navigation:navigation-ui-ktx:2.5.1'
104 |
105 | implementation 'androidx.multidex:multidex:2.0.1'
106 | implementation 'androidx.exifinterface:exifinterface:1.3.3'
107 | implementation 'androidx.preference:preference-ktx:1.2.0'
108 |
109 | // import ffmpeg-kit-full if building with audioSupport
110 | // else import ffmpeg-kit-min
111 | fullImplementation 'com.arthenica:ffmpeg-kit-full-gpl:5.1'
112 | videoImplementation 'com.arthenica:ffmpeg-kit-min-gpl:5.1'
113 |
114 | implementation 'com.jakewharton.timber:timber:5.0.1'
115 |
116 | testImplementation 'junit:junit:4.13.2'
117 | androidTestImplementation 'androidx.test.ext:junit:1.1.3'
118 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
119 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/caydey/ffshare/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.caydey.ffshare
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.caydey.sharemediacompressed", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
16 |
21 |
24 |
25 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
38 |
41 |
42 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
67 |
70 |
71 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caydey/ffshare/a436ad5d5667e0276ff2588b96424287b1d7f872/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/java/com/caydey/ffshare/App.kt:
--------------------------------------------------------------------------------
1 | package com.caydey.ffshare
2 |
3 | import androidx.multidex.MultiDexApplication
4 | import timber.log.Timber
5 |
6 | class App: MultiDexApplication() {
7 | companion object {
8 | var versionName = ""
9 | }
10 | private val settingsVersionUpdater = SettingsVersionUpdater(this)
11 | override fun onCreate() {
12 | super.onCreate()
13 |
14 | // save version name as static variable for use with Log class and MainActivity classes
15 | @Suppress("DEPRECATION")
16 | versionName = packageManager.getPackageInfo(applicationContext.packageName, 0).versionName
17 |
18 | // check if there has been a version change and if it requires the settings to be changed
19 | settingsVersionUpdater.check()
20 |
21 | if (BuildConfig.DEBUG) {
22 | Timber.plant(Timber.DebugTree())
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/caydey/ffshare/CacheCleanUpReceiver.kt:
--------------------------------------------------------------------------------
1 | package com.caydey.ffshare
2 |
3 | import android.app.AlarmManager
4 | import android.app.PendingIntent
5 | import android.content.BroadcastReceiver
6 | import android.content.Context
7 | import android.content.Intent
8 | import timber.log.Timber
9 | import java.io.File
10 |
11 | class CacheCleanUpReceiver: BroadcastReceiver() {
12 | override fun onReceive(context: Context, intent: Intent) {
13 | /*
14 | Cache structure
15 | /media/
16 | UUID/custom-name.mp4
17 | UUID/custom-name.mp4
18 | UUID/UUID.jpg
19 | UUID/UUID.jpg
20 | */
21 |
22 | Timber.d("Cleaning up cache")
23 |
24 | val mediaDir = File(context.cacheDir, "media")
25 | val cacheFiles = mediaDir.listFiles()
26 |
27 | cacheFiles?: return
28 |
29 |
30 | for (cacheFile in cacheFiles) {
31 | // media file older that 1 hour
32 | if (System.currentTimeMillis() - cacheFile.lastModified() > HOUR) {
33 | Timber.d("Deleting '%s'", cacheFile)
34 |
35 | cacheFile.deleteRecursively()
36 | }
37 | }
38 |
39 | // re-scan directory checking if it is empty
40 | if (mediaDir.listFiles()?.isEmpty() == true) {
41 | Timber.d("Cache folder empty, canceling cleanup alarm")
42 | // cancel alarm scheduler as there is no more cache files to cleanup
43 | val sender = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_CANCEL_CURRENT)
44 | val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager?
45 | alarmManager?.cancel(sender)
46 | }
47 | }
48 | companion object {
49 | private const val HOUR = 60 * 60 * 1_000
50 | }
51 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/caydey/ffshare/HandleMediaActivity.kt:
--------------------------------------------------------------------------------
1 | package com.caydey.ffshare
2 |
3 | import android.app.AlarmManager
4 | import android.app.PendingIntent
5 | import android.content.Context
6 | import android.content.Intent
7 | import android.net.Uri
8 | import android.os.Bundle
9 | import android.os.SystemClock
10 | import android.view.WindowManager
11 | import android.widget.Toast
12 | import androidx.appcompat.app.AppCompatActivity
13 | import com.caydey.ffshare.extensions.parcelable
14 | import com.caydey.ffshare.extensions.parcelableArrayList
15 | import com.caydey.ffshare.utils.MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE
16 | import com.caydey.ffshare.utils.MediaCompressor
17 | import com.caydey.ffshare.utils.Utils
18 | import timber.log.Timber
19 |
20 |
21 | class HandleMediaActivity : AppCompatActivity() {
22 | // by lazy means load when variable is used, lazy-loading helps performance
23 | // also without it there is a null error for applicationContext
24 | private val mediaCompressor: MediaCompressor by lazy { MediaCompressor(applicationContext) }
25 | private val utils: Utils by lazy { Utils(applicationContext) }
26 |
27 | override fun onCreate(savedInstanceState: Bundle?) {
28 | super.onCreate(savedInstanceState)
29 | setContentView(R.layout.activity_handle_media)
30 |
31 | window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
32 |
33 | if (utils.isReadPermissionGranted) {
34 | onMediaReceive()
35 | } else {
36 | Timber.d("Requesting read permissions")
37 | utils.requestReadPermissions(this)
38 | }
39 | }
40 |
41 | override fun finish() {
42 | mediaCompressor.cancelAllOperations()
43 | scheduleCacheCleanup()
44 | super.finish()
45 | }
46 |
47 | override fun onStop() {
48 | mediaCompressor.cancelAllOperations()
49 | super.onStop()
50 | }
51 |
52 | override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
53 | super.onRequestPermissionsResult(requestCode, permissions, grantResults)
54 | // first time running app user is requested to allow app to read external storage,
55 | // after clicking "allow" the app will continue handling media it was shared
56 | if (requestCode == MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE) {
57 | Timber.d("Read permissions granted, continuing...")
58 | onMediaReceive()
59 | }
60 | }
61 |
62 | private fun onMediaReceive() {
63 | // "intent" variable is the shared item
64 | val receivedMedia =
65 | when (intent.action) {
66 | Intent.ACTION_SEND -> arrayListOf(intent.parcelable(Intent.EXTRA_STREAM)!!)
67 | Intent.ACTION_SEND_MULTIPLE -> intent.parcelableArrayList(Intent.EXTRA_STREAM)!!
68 | else -> ArrayList()
69 | }
70 |
71 | // unable to get file from intent
72 | if (receivedMedia.isEmpty()) {
73 | Toast.makeText(this, getString(R.string.error_no_uri_intent), Toast.LENGTH_LONG).show()
74 | Timber.d("No files found in shared intent")
75 | finish()
76 | } else {
77 | // callback
78 | mediaCompressor.compressFiles(this, receivedMedia) { compressedMedia ->
79 | if (compressedMedia.isNotEmpty()) {
80 | shareMedia(compressedMedia)
81 | }
82 | finish()
83 | }
84 | }
85 | }
86 |
87 | private fun shareMedia(mediaUris: ArrayList) {
88 | val shareIntent = Intent()
89 |
90 | // temp permissions for other app to view file
91 | shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
92 |
93 | // add compressed media files
94 | if (mediaUris.size == 1) {
95 | Timber.d("Creating share intent for single item")
96 | shareIntent.action = Intent.ACTION_SEND
97 | shareIntent.putExtra(Intent.EXTRA_STREAM, mediaUris[0])
98 | } else {
99 | Timber.d("Creating share intent for multiple items")
100 | shareIntent.action = Intent.ACTION_SEND_MULTIPLE
101 | shareIntent.putExtra(Intent.EXTRA_STREAM, mediaUris)
102 | }
103 |
104 | // set mime for each file
105 | mediaUris.forEach { mediaUri ->
106 | shareIntent.setDataAndType(mediaUri, contentResolver.getType(mediaUri))
107 | }
108 |
109 | val chooser = Intent.createChooser(shareIntent, "media")
110 | startActivity(chooser)
111 | }
112 |
113 | private fun scheduleCacheCleanup() {
114 | Timber.d("Scheduling cleanup alarm")
115 | val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
116 | val intent = Intent(applicationContext, CacheCleanUpReceiver::class.java)
117 | val pendingIntent = PendingIntent.getBroadcast(applicationContext, 0, intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_CANCEL_CURRENT)
118 |
119 | // every 12 hours clear cache
120 | alarmManager.setInexactRepeating(
121 | AlarmManager.ELAPSED_REALTIME_WAKEUP,
122 | SystemClock.elapsedRealtime(),
123 | AlarmManager.INTERVAL_HALF_DAY,
124 | pendingIntent
125 | )
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/app/src/main/java/com/caydey/ffshare/LogItemDialog.kt:
--------------------------------------------------------------------------------
1 | package com.caydey.ffshare
2 |
3 | import android.app.Dialog
4 | import android.content.ClipData
5 | import android.content.ClipboardManager
6 | import android.content.Context
7 | import android.content.Context.CLIPBOARD_SERVICE
8 | import android.os.Bundle
9 | import android.text.method.ScrollingMovementMethod
10 | import android.widget.Button
11 | import android.widget.TextView
12 | import android.widget.Toast
13 | import com.caydey.ffshare.utils.logs.Log
14 |
15 | class LogItemDialog(context: Context, private val log: Log) : Dialog(context) {
16 | override fun onCreate(savedInstanceState: Bundle?) {
17 | super.onCreate(savedInstanceState)
18 | setContentView(R.layout.log_item_dialog)
19 |
20 | val txtFfmpegOutput = findViewById(R.id.logFfmpegOutput)
21 | val txtFfmpegTitle = findViewById(R.id.logFfmpegCommand)
22 |
23 | // scrollbars
24 | txtFfmpegOutput.movementMethod = ScrollingMovementMethod()
25 | txtFfmpegOutput.setHorizontallyScrolling(true)
26 |
27 | // content
28 | txtFfmpegTitle.text = log.command
29 | txtFfmpegOutput.text = log.ffmpeg_output
30 |
31 | findViewById