Merge branch 'security_suggestions3' into 'master'
Refactors and correctness improvements See merge request pixeldroid/PixelDroid!468
This commit is contained in:
commit
56b2d97889
@ -3,11 +3,6 @@ image: registry.gitlab.com/fdroid/ci-images-client
|
||||
before_script:
|
||||
- export GRADLE_USER_HOME=`pwd`/.gradle
|
||||
|
||||
cache:
|
||||
paths:
|
||||
- .gradle/wrapper
|
||||
- .gradle/caches
|
||||
|
||||
# Basic android and gradle stuff
|
||||
# Check linting
|
||||
lintDebug:
|
||||
@ -18,7 +13,13 @@ lintDebug:
|
||||
- apt-get install -y openjdk-11-jdk-headless
|
||||
- update-alternatives --auto java
|
||||
- ./gradlew checkLicenses
|
||||
- ./gradlew -Pci --console=plain :app:lintDebug -PbuildDir=lint
|
||||
- ./gradlew -Pci --console=plain :app:lintDebug -PbuildDir=lint --write-verification-metadata sha256
|
||||
- git diff --quiet gradle/verification-metadata.xml || (echo 'Verification of dependencies failed!' && exit 1)
|
||||
artifacts:
|
||||
when: on_failure
|
||||
paths:
|
||||
- gradle/verification-metadata.xml
|
||||
|
||||
|
||||
# Make Project
|
||||
assembleDebug:
|
||||
|
@ -15,6 +15,7 @@ jacoco.toolVersion = "0.8.7"
|
||||
|
||||
android {
|
||||
|
||||
namespace 'org.pixeldroid.app'
|
||||
compileSdkVersion 32
|
||||
buildToolsVersion '31.0.0'
|
||||
compileOptions {
|
||||
@ -27,7 +28,6 @@ android {
|
||||
freeCompilerArgs += ["-opt-in=kotlin.RequiresOptIn"]
|
||||
}
|
||||
defaultConfig {
|
||||
applicationId "org.pixeldroid.app"
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 32
|
||||
versionCode 17
|
||||
|
@ -515,11 +515,6 @@
|
||||
license: The Apache Software License, Version 2.0
|
||||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
url: http://tools.android.com
|
||||
- artifact: androidx.databinding:databinding-ktx:+
|
||||
name: databinding-ktx
|
||||
copyrightHolder: Google Inc.
|
||||
license: The Apache Software License, Version 2.0
|
||||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
- artifact: androidx.lifecycle:lifecycle-process:+
|
||||
name: lifecycle-process
|
||||
copyrightHolder: Google Inc.
|
||||
@ -670,11 +665,6 @@
|
||||
license: The Apache Software License, Version 2.0
|
||||
licenseUrl: https://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
url: https://github.com/Kotlin/kotlinx.coroutines
|
||||
- artifact: androidx.databinding:viewbinding:+
|
||||
name: viewbinding
|
||||
copyrightHolder: Google Inc.
|
||||
license: The Apache Software License, Version 2.0
|
||||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
- artifact: org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:+
|
||||
name: kotlinx-coroutines-core-jvm
|
||||
copyrightHolder: JetBrains s.r.o. and contributors
|
||||
@ -767,16 +757,6 @@
|
||||
license: The Apache Software License, Version 2.0
|
||||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
url: https://developer.android.com/jetpack/androidx
|
||||
- artifact: androidx.databinding:databinding-adapters:+
|
||||
name: databinding-adapters
|
||||
copyrightHolder: Google Inc
|
||||
license: The Apache Software License, Version 2.0
|
||||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
- artifact: androidx.databinding:databinding-runtime:+
|
||||
name: databinding-runtime
|
||||
copyrightHolder: Google Inc
|
||||
license: The Apache Software License, Version 2.0
|
||||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
- artifact: androidx.databinding:databinding-common:+
|
||||
name: databinding-common
|
||||
copyrightHolder: Google Inc
|
||||
|
2
app/proguard-rules.pro
vendored
2
app/proguard-rules.pro
vendored
@ -66,6 +66,8 @@
|
||||
-assumenosideeffects class android.util.Log {
|
||||
public static *** getStackTraceString(...);
|
||||
public static *** d(...);
|
||||
public static *** e(...);
|
||||
public static *** println(...);
|
||||
public static *** w(...);
|
||||
public static *** v(...);
|
||||
public static *** i(...);
|
||||
|
@ -68,19 +68,19 @@ class DrawerMenuTest {
|
||||
// Start the screen of your activity.
|
||||
onView(withText(R.string.menu_settings)).perform(click())
|
||||
val themes = getInstrumentation().targetContext.resources.getStringArray(R.array.theme_entries)
|
||||
//select theme modes
|
||||
// Select theme modes
|
||||
onView(withText(R.string.theme_title)).perform(click())
|
||||
onView(withText(themes[2])).perform(click())
|
||||
|
||||
//Select an other theme
|
||||
// Select an other theme
|
||||
onView(withText(R.string.theme_title)).perform(click())
|
||||
onView(withText(themes[0])).perform(click())
|
||||
|
||||
//Select the last theme
|
||||
// Select the last theme
|
||||
onView(withText(R.string.theme_title)).perform(click())
|
||||
onView(withText(themes[1])).perform(click())
|
||||
|
||||
//Check that we are back in the settings page
|
||||
// Check that we are back in the settings page
|
||||
onView(withText(R.string.theme_header)).check(matches(isDisplayed()))
|
||||
}
|
||||
|
||||
|
@ -65,12 +65,12 @@ class HomeFeedTest {
|
||||
@Test
|
||||
@RepeatTest
|
||||
fun clickingTabOnAlbumShowsNextPhoto() {
|
||||
//Wait for the feed to load
|
||||
// Wait for the feed to load
|
||||
waitForView(R.id.albumPager)
|
||||
|
||||
activityScenario.onActivity {
|
||||
a -> run {
|
||||
//Pick the second photo
|
||||
// Pick the second photo
|
||||
a.findViewById<ViewPager2>(R.id.albumPager).currentItem = 2
|
||||
}
|
||||
}
|
||||
@ -80,7 +80,7 @@ class HomeFeedTest {
|
||||
@Test
|
||||
@RepeatTest
|
||||
fun tabReClickScrollUp() {
|
||||
//Wait for the feed to load
|
||||
// Wait for the feed to load
|
||||
waitForView(R.id.albumPager)
|
||||
|
||||
onView(withId(R.id.list)).perform(scrollToPosition<StatusViewHolder>(2))
|
||||
@ -94,7 +94,7 @@ class HomeFeedTest {
|
||||
@Test
|
||||
@RepeatTest
|
||||
fun hashtag() {
|
||||
//Wait for the feed to load
|
||||
// Wait for the feed to load
|
||||
waitForView(R.id.albumPager)
|
||||
|
||||
onView(allOf(withClassName(endsWith("RecyclerView")), not(withId(R.id.material_drawer_recycler_view))))
|
||||
@ -126,27 +126,27 @@ class HomeFeedTest {
|
||||
@Test
|
||||
fun doubleTapLikerWorks() {
|
||||
Thread.sleep(1000)
|
||||
//Get initial like count
|
||||
// Get initial like count
|
||||
val likes = getText(first(withId(R.id.nlikes)))
|
||||
val nLikes = likes!!.split(" ")[0].toInt()
|
||||
|
||||
//Remove sensitive media warning
|
||||
// Remove sensitive media warning
|
||||
onView(withId(R.id.list))
|
||||
.perform(actionOnItemAtPosition<StatusViewHolder>
|
||||
(0, clickChildViewWithId(R.id.sensitiveWarning)))
|
||||
Thread.sleep(100)
|
||||
|
||||
//Like the post
|
||||
// Like the post
|
||||
onView(withId(R.id.list))
|
||||
.perform(actionOnItemAtPosition<StatusViewHolder>
|
||||
(0, clickChildViewWithId(R.id.postPicture)))
|
||||
onView(withId(R.id.list))
|
||||
.perform(actionOnItemAtPosition<StatusViewHolder >
|
||||
(0, clickChildViewWithId(R.id.postPicture)))
|
||||
//...
|
||||
// ...
|
||||
Thread.sleep(100)
|
||||
|
||||
//Profit
|
||||
// Profit
|
||||
onView(first(withId(R.id.nlikes))).check(matches((withText("${nLikes + 1} Likes"))))
|
||||
}
|
||||
|
||||
@ -216,7 +216,7 @@ class HomeFeedTest {
|
||||
|
||||
@Test
|
||||
fun clickingViewCommentShowsTheComments() {
|
||||
//Open the comment section
|
||||
// Open the comment section
|
||||
onView(withId(R.id.list))
|
||||
.perform(actionOnItemAtPosition<StatusViewHolder>
|
||||
(0, clickChildViewWithId(R.id.viewComments)))
|
||||
@ -227,7 +227,7 @@ class HomeFeedTest {
|
||||
|
||||
@Test
|
||||
fun clickingViewCommentFails() {
|
||||
//Open the comment section
|
||||
// Open the comment section
|
||||
onView(withId(R.id.list))
|
||||
.perform(actionOnItemAtPosition<StatusViewHolder>
|
||||
(2, clickChildViewWithId(R.id.viewComments)))
|
||||
|
@ -197,11 +197,11 @@ class MockedServerTest {
|
||||
waitForView(R.id.view_pager)
|
||||
|
||||
onView(withId(R.id.view_pager))
|
||||
.perform(ViewActions.swipeLeft()) // notifications
|
||||
.perform(ViewActions.swipeLeft()) // camera
|
||||
.perform(ViewActions.swipeLeft()) // search
|
||||
.perform(ViewActions.swipeLeft()) // homepage
|
||||
.perform(ViewActions.swipeLeft()) // should stop at homepage
|
||||
.perform(ViewActions.swipeLeft()) // Notifications
|
||||
.perform(ViewActions.swipeLeft()) // Camera
|
||||
.perform(ViewActions.swipeLeft()) // Search
|
||||
.perform(ViewActions.swipeLeft()) // Homepage
|
||||
.perform(ViewActions.swipeLeft()) // Should stop at homepage
|
||||
activityScenario.onActivity {
|
||||
assert(it.findViewById<BottomNavigationView>(R.id.tabs).selectedItemId == R.id.page_5)
|
||||
}
|
||||
@ -211,16 +211,16 @@ class MockedServerTest {
|
||||
fun swipingPublicTimelineWorks() {
|
||||
activityScenario.onActivity {
|
||||
it.findViewById<BottomNavigationView>(R.id.tabs).selectedItemId = R.id.page_5
|
||||
} // go to the last tab
|
||||
} // Go to the last tab
|
||||
|
||||
waitForView(R.id.view_pager)
|
||||
|
||||
onView(withId(R.id.view_pager))
|
||||
.perform(ViewActions.swipeRight()) // notifications
|
||||
.perform(ViewActions.swipeRight()) // camera
|
||||
.perform(ViewActions.swipeRight()) // search
|
||||
.perform(ViewActions.swipeRight()) // homepage
|
||||
.perform(ViewActions.swipeRight()) // should stop at homepage
|
||||
.perform(ViewActions.swipeRight()) // Notifications
|
||||
.perform(ViewActions.swipeRight()) // Camera
|
||||
.perform(ViewActions.swipeRight()) // Search
|
||||
.perform(ViewActions.swipeRight()) // Homepage
|
||||
.perform(ViewActions.swipeRight()) // Should stop at homepage
|
||||
|
||||
activityScenario.onActivity {
|
||||
assert(it.findViewById<BottomNavigationView>(R.id.tabs).selectedItemId == R.id.page_1)
|
||||
|
@ -101,7 +101,7 @@ class NotificationWorkerTest {
|
||||
// Check worker returns success (which doesn't mean much, but is a good start)
|
||||
MatcherAssert.assertThat(result, CoreMatchers.`is`(ListenableWorker.Result.success()))
|
||||
|
||||
//Open notification shade
|
||||
// Open notification shade
|
||||
uiDevice.openNotification()
|
||||
uiDevice.wait(Until.hasObject(By.textStartsWith(expectedAppName)), 5000)
|
||||
|
||||
|
@ -96,7 +96,7 @@ class PostCreationActivityTest {
|
||||
@Ignore("Annoying to deal with and also sometimes the intent is not working as it should")
|
||||
fun createPost() {
|
||||
onView(withId(R.id.post_creation_send_button)).perform(click())
|
||||
// should send on main activity
|
||||
// Should send on main activity
|
||||
Thread.sleep(3000)
|
||||
onView(withId(R.id.list)).check(matches(isDisplayed()))
|
||||
}
|
||||
@ -105,7 +105,7 @@ class PostCreationActivityTest {
|
||||
fun errorShown() {
|
||||
testScenario!!.onActivity { a -> a.upload_error.visibility = VISIBLE }
|
||||
onView(withId(R.id.retry_upload_button)).perform(click())
|
||||
// should send on main activity
|
||||
// Should send on main activity
|
||||
onView(withId(R.id.retry_upload_button)).check(matches(not(isDisplayed())))
|
||||
}
|
||||
*/
|
||||
|
@ -60,7 +60,7 @@ class PostCreationFragmentTest {
|
||||
|
||||
private val expectedIntent: Matcher<Intent> = hasAction(Intent.ACTION_CHOOSER)
|
||||
|
||||
// image choosing intent
|
||||
// Image choosing intent
|
||||
@Test
|
||||
fun galleryButtonLaunchesGalleryIntent() {
|
||||
waitForView(R.id.photo_view_button)
|
||||
|
@ -51,7 +51,7 @@ class ProfileTest {
|
||||
@Test
|
||||
fun clickFollowButton() {
|
||||
if (onView(ViewMatchers.withText("Unfollow")).isDisplayed()) {
|
||||
//Currently following
|
||||
// Currently following
|
||||
|
||||
// Unfollow
|
||||
follow("Follow")
|
||||
@ -59,7 +59,7 @@ class ProfileTest {
|
||||
// Follow
|
||||
follow("Unfollow")
|
||||
} else if (onView(ViewMatchers.withText("Follow")).isDisplayed()){
|
||||
//Currently not following
|
||||
// Currently not following
|
||||
|
||||
// Follow
|
||||
follow("Unfollow")
|
||||
@ -89,7 +89,7 @@ class ProfileTest {
|
||||
|
||||
waitForView(R.id.editButton)
|
||||
|
||||
//Check that our own profile opened
|
||||
// Check that our own profile opened
|
||||
onView(withId(R.id.editButton)).isDisplayed()
|
||||
}
|
||||
|
||||
|
@ -106,7 +106,7 @@ private fun waitForViewViewAction(viewId: Int, viewMatcher: Matcher<View>): View
|
||||
// Loops the main thread for a specified period of time.
|
||||
// Control may not return immediately, instead it'll return after the provided delay has passed and the queue is in an idle state again.
|
||||
uiController.loopMainThreadForAtLeast(100)
|
||||
} while (System.currentTimeMillis() < endTime) // in case of a timeout we throw an exception - test fails
|
||||
} while (System.currentTimeMillis() < endTime) // In case of a timeout we throw an exception - test fails
|
||||
throw PerformException.Builder()
|
||||
.withCause(TimeoutException())
|
||||
.withActionDescription(this.description)
|
||||
@ -228,7 +228,7 @@ fun atPosition(position: Int, itemMatcher: Matcher<View?>): Matcher<View?> {
|
||||
|
||||
override fun matchesSafely(view: RecyclerView): Boolean {
|
||||
val viewHolder = view.findViewHolderForAdapterPosition(position)
|
||||
?: // has no item on such position
|
||||
?: // Has no item on such position
|
||||
return false
|
||||
return itemMatcher.matches(viewHolder.itemView)
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="org.pixeldroid.app">
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
File diff suppressed because one or more lines are too long
@ -39,7 +39,7 @@ import org.pixeldroid.app.postCreation.photoEdit.VideoEditActivity
|
||||
import org.pixeldroid.app.utils.BaseThemedWithoutBarActivity
|
||||
import org.pixeldroid.app.utils.db.entities.InstanceDatabaseEntity
|
||||
import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity
|
||||
import org.pixeldroid.app.utils.ffmpegSafeUri
|
||||
import org.pixeldroid.app.utils.ffmpegCompliantUri
|
||||
import org.pixeldroid.app.utils.fileExtension
|
||||
import org.pixeldroid.app.utils.getMimeType
|
||||
import java.io.File
|
||||
@ -329,25 +329,26 @@ class PostCreationActivity : BaseThemedWithoutBarActivity() {
|
||||
|
||||
// Having a meaningful suffix is necessary so that ffmpeg knows what to put in output
|
||||
val suffix = originalUri.fileExtension(contentResolver)
|
||||
val file = File.createTempFile("temp_video", ".$suffix")
|
||||
//val file = File.createTempFile("temp_video", ".webm")
|
||||
val file = File.createTempFile("temp_video", ".$suffix", cacheDir)
|
||||
//val file = File.createTempFile("temp_video", ".webm", cacheDir)
|
||||
model.trackTempFile(file)
|
||||
val fileUri = file.toUri()
|
||||
val outputVideoPath = ffmpegSafeUri(fileUri)
|
||||
val outputVideoPath = ffmpegCompliantUri(fileUri)
|
||||
|
||||
val inputUri = model.getPhotoData().value!![position].imageUri
|
||||
|
||||
val inputSafePath = ffmpegSafeUri(inputUri)
|
||||
val ffmpegCompliantUri: String = ffmpegCompliantUri(inputUri)
|
||||
|
||||
val mediaInformation: MediaInformation? = FFprobeKit.getMediaInformation(ffmpegSafeUri(inputUri)).mediaInformation
|
||||
val mediaInformation: MediaInformation? = FFprobeKit.getMediaInformation(ffmpegCompliantUri(inputUri)).mediaInformation
|
||||
val totalVideoDuration = mediaInformation?.duration?.toFloatOrNull()
|
||||
|
||||
val mutedString = if(muted) "-an" else ""
|
||||
val startString = if(videoStart != null) "-ss $videoStart" else ""
|
||||
val mutedString = if(muted) "-an" else null
|
||||
val startString: List<String?> = if(videoStart != null) listOf("-ss", "$videoStart") else listOf(null, null)
|
||||
|
||||
val endString = if(videoEnd != null) "-to ${videoEnd - (videoStart ?: 0f)}" else ""
|
||||
val endString: List<String?> = if(videoEnd != null) listOf("-to", "${videoEnd - (videoStart ?: 0f)}") else listOf(null, null)
|
||||
|
||||
val session: FFmpegSession = FFmpegKit.executeAsync("$startString -i $inputSafePath $endString -c copy $mutedString -y $outputVideoPath",
|
||||
val session: FFmpegSession =
|
||||
FFmpegKit.executeWithArgumentsAsync(listOfNotNull(startString[0], startString[1], "-i", ffmpegCompliantUri, endString[0], endString[1], "-c", "copy", mutedString, "-y", outputVideoPath).toTypedArray(),
|
||||
//val session: FFmpegSession = FFmpegKit.executeAsync("$startString -i $inputSafePath $endString -c:v libvpx-vp9 -c:a copy -an -y $outputVideoPath",
|
||||
{ session ->
|
||||
val returnCode = session.returnCode
|
||||
|
@ -392,14 +392,14 @@ class CameraFragment : BaseFragment() {
|
||||
// Get a stable reference of the modifiable image capture use case
|
||||
imageCapture?.let { imageCapture ->
|
||||
|
||||
// Create output file to hold the image
|
||||
// Create output file to hold the image. CameraX saves a JPEG image to this file,
|
||||
// so it makes no sense to use another extension here
|
||||
val photoFile = File.createTempFile(
|
||||
"cachedPhoto", ".png", context?.cacheDir
|
||||
"cachedPhoto", ".jpg", context?.cacheDir
|
||||
)
|
||||
|
||||
// Setup image capture metadata
|
||||
val metadata = Metadata().apply {
|
||||
|
||||
// Mirror image when using the front camera
|
||||
isReversedHorizontal = lensFacing == CameraSelector.LENS_FACING_FRONT
|
||||
}
|
||||
|
@ -291,11 +291,13 @@ class PhotoEditActivity : BaseThemedWithBarActivity() {
|
||||
setToolbarWidgetColor(this@PhotoEditActivity.getColorFromAttr(R.attr.colorOnSurface))
|
||||
setToolbarColor(this@PhotoEditActivity.getColorFromAttr(R.attr.colorSurface))
|
||||
setActiveControlsWidgetColor(this@PhotoEditActivity.getColorFromAttr(R.attr.colorPrimary))
|
||||
setFreeStyleCropEnabled(true)
|
||||
}
|
||||
val uCrop: UCrop = UCrop.of(initialUri!!, Uri.fromFile(file)).withOptions(options)
|
||||
uCrop.start(this)
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if(resultCode == Activity.RESULT_OK) {
|
||||
|
@ -29,7 +29,7 @@ import org.pixeldroid.app.databinding.ActivityVideoEditBinding
|
||||
import org.pixeldroid.app.postCreation.PostCreationActivity
|
||||
import org.pixeldroid.app.postCreation.carousel.dpToPx
|
||||
import org.pixeldroid.app.utils.BaseThemedWithBarActivity
|
||||
import org.pixeldroid.app.utils.ffmpegSafeUri
|
||||
import org.pixeldroid.app.utils.ffmpegCompliantUri
|
||||
import java.io.File
|
||||
|
||||
|
||||
@ -61,7 +61,7 @@ class VideoEditActivity : BaseThemedWithBarActivity() {
|
||||
val uri = intent.getParcelableExtra<Uri>(PhotoEditActivity.PICTURE_URI)!!
|
||||
videoPosition = intent.getIntExtra(PhotoEditActivity.PICTURE_POSITION, -1)
|
||||
|
||||
val inputVideoPath = ffmpegSafeUri(uri)
|
||||
val inputVideoPath = ffmpegCompliantUri(uri)
|
||||
val mediaInformation: MediaInformation? = FFprobeKit.getMediaInformation(inputVideoPath).mediaInformation
|
||||
|
||||
binding.muter.setOnClickListener {
|
||||
@ -229,18 +229,19 @@ class VideoEditActivity : BaseThemedWithBarActivity() {
|
||||
thumbnail: ImageView,
|
||||
thumbTime: Float,
|
||||
) {
|
||||
val file = File.createTempFile("temp_img", ".bmp")
|
||||
val file = File.createTempFile("temp_img", ".bmp", cacheDir)
|
||||
tempFiles.add(file)
|
||||
val fileUri = file.toUri()
|
||||
val inputSafePath = ffmpegSafeUri(inputUri)
|
||||
val ffmpegCompliantUri = ffmpegCompliantUri(inputUri)
|
||||
|
||||
val outputImagePath =
|
||||
if(fileUri.toString().startsWith("content://"))
|
||||
FFmpegKitConfig.getSafParameterForWrite(this, fileUri)
|
||||
else fileUri.toString()
|
||||
val session = FFmpegKit.executeAsync(
|
||||
"-noaccurate_seek -ss $thumbTime -i $inputSafePath -vf scale=${thumbnail.width}:${thumbnail.height} -frames:v 1 -f image2 -y $outputImagePath",
|
||||
{ session ->
|
||||
val session = FFmpegKit.executeWithArgumentsAsync(arrayOf(
|
||||
"-noaccurate_seek", "-ss", "$thumbTime", "-i", ffmpegCompliantUri, "-vf",
|
||||
"scale=${thumbnail.width}:${thumbnail.height}",
|
||||
"-frames:v", "1", "-f", "image2", "-y", outputImagePath), { session ->
|
||||
val state = session.state
|
||||
val returnCode = session.returnCode
|
||||
|
||||
@ -254,7 +255,7 @@ class VideoEditActivity : BaseThemedWithBarActivity() {
|
||||
// CALLED WHEN SESSION IS EXECUTED
|
||||
Log.d("VideoEditActivity", "FFmpeg process exited with state $state and rc $returnCode.${session.failStackTrace}")
|
||||
},
|
||||
{/* CALLED WHEN SESSION PRINTS LOGS */ }) { /*CALLED WHEN SESSION GENERATES STATISTICS*/ }
|
||||
{/* CALLED WHEN SESSION PRINTS LOGS */ }, { /*CALLED WHEN SESSION GENERATES STATISTICS*/ })
|
||||
sessionList.add(session.sessionId)
|
||||
}
|
||||
|
||||
|
@ -226,7 +226,7 @@ class NotificationsFragment : CachedFeedFragment<Notification>() {
|
||||
)
|
||||
}
|
||||
|
||||
//Convert HTML to clickable text
|
||||
// Convert HTML to clickable text
|
||||
postDescription.text =
|
||||
parseHTMLText(
|
||||
notification?.status?.content ?: "",
|
||||
|
@ -45,7 +45,7 @@ class NotificationsRemoteMediator @Inject constructor(
|
||||
val maxId = when (loadType) {
|
||||
LoadType.REFRESH -> null
|
||||
LoadType.PREPEND -> {
|
||||
//No prepend for the moment, might be nice to add later
|
||||
// No prepend for the moment, might be nice to add later
|
||||
return MediatorResult.Success(endOfPaginationReached = true)
|
||||
}
|
||||
LoadType.APPEND -> state.lastItemOrNull()?.id
|
||||
@ -67,7 +67,7 @@ class NotificationsRemoteMediator @Inject constructor(
|
||||
val endOfPaginationReached = apiResponse.isEmpty()
|
||||
|
||||
db.withTransaction {
|
||||
// clear table in the database
|
||||
// Clear table in the database
|
||||
if (loadType == LoadType.REFRESH) {
|
||||
db.notificationDao().clearFeedContent(user.user_id, user.instance_uri)
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ class HomeFeedRemoteMediator @Inject constructor(
|
||||
val maxId = when (loadType) {
|
||||
LoadType.REFRESH -> null
|
||||
LoadType.PREPEND -> {
|
||||
//No prepend for the moment, might be nice to add later
|
||||
// No prepend for the moment, might be nice to add later
|
||||
return MediatorResult.Success(endOfPaginationReached = true)
|
||||
}
|
||||
LoadType.APPEND -> state.lastItemOrNull()?.id
|
||||
@ -52,7 +52,7 @@ class HomeFeedRemoteMediator @Inject constructor(
|
||||
val endOfPaginationReached = apiResponse.isEmpty()
|
||||
|
||||
db.withTransaction {
|
||||
// clear table in the database
|
||||
// Clear table in the database
|
||||
if (loadType == LoadType.REFRESH) {
|
||||
db.homePostDao().clearFeedContent(user.user_id, user.instance_uri)
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ class PostFeedFragment<T: FeedContentDatabase>: CachedFeedFragment<T>() {
|
||||
|
||||
val view = super.onCreateView(inflater, container, savedInstanceState)
|
||||
|
||||
// get the view model
|
||||
// Get the view model
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
viewModel = ViewModelProvider(requireActivity(), ViewModelFactory(db, dao, mediator))[if(home) "home" else "public", FeedViewModel::class.java] as FeedViewModel<T>
|
||||
|
||||
|
@ -44,7 +44,7 @@ class PublicFeedRemoteMediator @Inject constructor(
|
||||
val maxId = when (loadType) {
|
||||
LoadType.REFRESH -> null
|
||||
LoadType.PREPEND -> {
|
||||
//No prepend for the moment, might be nice to add later
|
||||
// No prepend for the moment, might be nice to add later
|
||||
return MediatorResult.Success(endOfPaginationReached = true)
|
||||
}
|
||||
LoadType.APPEND -> state.lastItemOrNull()?.id
|
||||
@ -67,7 +67,7 @@ class PublicFeedRemoteMediator @Inject constructor(
|
||||
val endOfPaginationReached = apiResponse.isEmpty()
|
||||
|
||||
db.withTransaction {
|
||||
// clear table in the database
|
||||
// Clear table in the database
|
||||
if (loadType == LoadType.REFRESH) {
|
||||
db.publicPostDao().clearFeedContent(user.user_id, user.instance_uri)
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ class CommentFragment : UncachedFeedFragment<Status>() {
|
||||
|
||||
val view = super.onCreateView(inflater, container, savedInstanceState)
|
||||
|
||||
// get the view model
|
||||
// Get the view model
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
viewModel = ViewModelProvider(
|
||||
requireActivity(), ViewModelFactory(
|
||||
|
@ -35,7 +35,7 @@ class SearchAccountFragment : UncachedFeedFragment<Account>() {
|
||||
|
||||
val view = super.onCreateView(inflater, container, savedInstanceState)
|
||||
|
||||
// get the view model
|
||||
// Get the view model
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
viewModel = ViewModelProvider(requireActivity(), ViewModelFactory(
|
||||
SearchContentRepository<Account>(
|
||||
|
@ -43,7 +43,7 @@ class SearchHashtagFragment : UncachedFeedFragment<Tag>() {
|
||||
): View? {
|
||||
val view = super.onCreateView(inflater, container, savedInstanceState)
|
||||
|
||||
// get the view model
|
||||
// Get the view model
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
viewModel = ViewModelProvider(requireActivity(), ViewModelFactory(
|
||||
SearchContentRepository<Tag>(
|
||||
|
@ -19,8 +19,13 @@ import kotlin.math.withSign
|
||||
object BlurHashDecoder {
|
||||
|
||||
fun blurHashBitmap(resources: Resources, blurHash: String, width: Int?, height: Int?): BitmapDrawable {
|
||||
val ratioOr0 = (width?.toFloat() ?: 1f) / (height?.toFloat() ?: 1f)
|
||||
|
||||
// The call to `decode` is expensive (costs scale linearly on ratio or 1/ratio), so
|
||||
// the ratio should be contained within 1/100 and 100 (which seem reasonable)
|
||||
val ratioOr0 = ((width?.toFloat() ?: 1f) / (height?.toFloat() ?: 1f)).coerceIn(1/100f, 100f)
|
||||
|
||||
// Width and/or height may be 0 here (bad information sent by server).
|
||||
// In that case, we make a square 32x32
|
||||
val ratio = if (ratioOr0 == 0f) 1f else ratioOr0
|
||||
return BitmapDrawable(resources,
|
||||
decode(blurHash,
|
||||
@ -51,7 +56,7 @@ object BlurHashDecoder {
|
||||
} else {
|
||||
val from = 4 + i * 2
|
||||
val colorEnc = decode83(blurHash, from, from + 2)
|
||||
decodeAc(colorEnc, maxAc * punch)
|
||||
decodeAc(colorEnc, maxAc *punch)
|
||||
}
|
||||
}
|
||||
return composeBitmap(width, height, numCompX, numCompY, colors)
|
||||
|
@ -96,7 +96,7 @@ fun normalizeDomain(domain: String): String {
|
||||
.trim(Char::isWhitespace)
|
||||
}
|
||||
|
||||
fun Context.ffmpegSafeUri(inputUri: Uri?): String =
|
||||
fun Context.ffmpegCompliantUri(inputUri: Uri?): String =
|
||||
if (inputUri?.scheme == "content")
|
||||
FFmpegKitConfig.getSafParameterForRead(this, inputUri)
|
||||
else inputUri.toString()
|
||||
|
@ -25,7 +25,7 @@ import java.time.format.DateTimeFormatter
|
||||
|
||||
/*
|
||||
Implements the Pixelfed API
|
||||
https://docs.pixelfed.org/technical-documentation/api-v1.html
|
||||
https://docs.pixelfed.org/technical-documentation/api-v1
|
||||
However, since this is mostly based on the Mastodon API, the documentation there
|
||||
will be more useful: https://docs.joinmastodon.org/
|
||||
*/
|
||||
|
@ -8,7 +8,7 @@ interface InstanceDao {
|
||||
@Query("SELECT * FROM instances")
|
||||
fun getAll(): List<InstanceDatabaseEntity>
|
||||
|
||||
@Query("SELECT * FROM instances WHERE uri=:instanceUri LIMIT 1")
|
||||
@Query("SELECT * FROM instances WHERE uri=:instanceUri")
|
||||
fun getInstance(instanceUri: String): InstanceDatabaseEntity
|
||||
|
||||
/**
|
||||
|
@ -27,7 +27,7 @@ interface UserDao {
|
||||
@Query("SELECT * FROM users")
|
||||
fun getAll(): List<UserDatabaseEntity>
|
||||
|
||||
@Query("SELECT * FROM users WHERE isActive=1 LIMIT 1")
|
||||
@Query("SELECT * FROM users WHERE isActive=1")
|
||||
fun getActiveUser(): UserDatabaseEntity?
|
||||
|
||||
@Query("UPDATE users SET isActive=0")
|
||||
@ -39,6 +39,6 @@ interface UserDao {
|
||||
@Query("DELETE FROM users WHERE isActive=1")
|
||||
fun deleteActiveUsers()
|
||||
|
||||
@Query("SELECT * FROM users WHERE user_id=:id AND instance_uri=:instance_uri LIMIT 1")
|
||||
@Query("SELECT * FROM users WHERE user_id=:id AND instance_uri=:instance_uri")
|
||||
fun getUserWithId(id: String, instance_uri: String): UserDatabaseEntity
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.7.0'
|
||||
ext.kotlin_version = '1.7.10'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.3.0-beta05'
|
||||
classpath 'com.android.tools.build:gradle:7.3.0-rc01'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user