Migration from Dagger to Hilt
This commit is contained in:
parent
05cb615f15
commit
0aa3d86c11
|
@ -1,10 +1,13 @@
|
|||
import com.android.build.api.dsl.ManagedVirtualDevice
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'jacoco'
|
||||
apply plugin: "kotlin-parcelize"
|
||||
apply plugin: 'com.google.devtools.ksp'
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("com.google.dagger.hilt.android")
|
||||
id("kotlin-android")
|
||||
id("jacoco")
|
||||
id("kotlin-parcelize")
|
||||
id("com.google.devtools.ksp")
|
||||
}
|
||||
|
||||
android {
|
||||
|
||||
|
@ -184,6 +187,9 @@ dependencies {
|
|||
implementation 'com.google.dagger:dagger:2.50'
|
||||
ksp 'com.google.dagger:dagger-compiler:2.50'
|
||||
|
||||
implementation("com.google.dagger:hilt-android:2.50")
|
||||
ksp "com.google.dagger:hilt-compiler:2.50"
|
||||
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
||||
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
|
||||
|
|
|
@ -78,7 +78,7 @@ class MainActivity : BaseActivity() {
|
|||
private lateinit var header: AccountHeaderView
|
||||
private var user: UserDatabaseEntity? = null
|
||||
|
||||
private lateinit var model: MainActivityViewModel
|
||||
private val model: MainActivityViewModel by viewModels()
|
||||
|
||||
companion object {
|
||||
const val ADD_ACCOUNT_IDENTIFIER: Long = -13
|
||||
|
@ -111,12 +111,6 @@ class MainActivity : BaseActivity() {
|
|||
} else {
|
||||
sendTraceDroidStackTracesIfExist("contact@pixeldroid.org", this)
|
||||
|
||||
val _model: MainActivityViewModel by viewModels {
|
||||
MainActivityViewModelFactory(application)
|
||||
}
|
||||
model = _model
|
||||
|
||||
|
||||
setupDrawer()
|
||||
val tabs: List<() -> Fragment> = listOf(
|
||||
{
|
||||
|
@ -280,13 +274,13 @@ class MainActivity : BaseActivity() {
|
|||
|
||||
val remainingUsers = db.userDao().getAll()
|
||||
if (remainingUsers.isEmpty()){
|
||||
//no more users, start first-time login flow
|
||||
// No more users, start first-time login flow
|
||||
launchActivity(LoginActivity(), firstTime = true)
|
||||
} else {
|
||||
val newActive = remainingUsers.first()
|
||||
db.userDao().activateUser(newActive.user_id, newActive.instance_uri)
|
||||
apiHolder.setToCurrentUser()
|
||||
//relaunch the app
|
||||
// Relaunch the app
|
||||
launchActivity(MainActivity(), firstTime = true)
|
||||
}
|
||||
}
|
||||
|
@ -334,9 +328,11 @@ class MainActivity : BaseActivity() {
|
|||
}
|
||||
|
||||
private fun switchUser(userId: String, instance_uri: String) {
|
||||
db.userDao().deActivateActiveUsers()
|
||||
db.userDao().activateUser(userId, instance_uri)
|
||||
apiHolder.setToCurrentUser()
|
||||
db.runInTransaction{
|
||||
db.userDao().deActivateActiveUsers()
|
||||
db.userDao().activateUser(userId, instance_uri)
|
||||
apiHolder.setToCurrentUser()
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun primaryDrawerItem(block: PrimaryDrawerItem.() -> Unit): PrimaryDrawerItem {
|
||||
|
|
|
@ -1,25 +1,22 @@
|
|||
package org.pixeldroid.app
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import org.pixeldroid.app.utils.PixelDroidApplication
|
||||
import org.pixeldroid.app.utils.db.AppDatabase
|
||||
import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity
|
||||
import javax.inject.Inject
|
||||
|
||||
class MainActivityViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
@Inject
|
||||
lateinit var db: AppDatabase
|
||||
@HiltViewModel
|
||||
class MainActivityViewModel @Inject constructor(
|
||||
private val db: AppDatabase
|
||||
): ViewModel() {
|
||||
|
||||
// Mutable state flow that will be used internally in the ViewModel, empty list is given as initial value.
|
||||
private val _users = MutableStateFlow(emptyList<UserDatabaseEntity>())
|
||||
|
@ -29,7 +26,6 @@ class MainActivityViewModel(application: Application) : AndroidViewModel(applica
|
|||
|
||||
|
||||
init {
|
||||
(application as PixelDroidApplication).getAppComponent().inject(this)
|
||||
getUsers()
|
||||
}
|
||||
|
||||
|
@ -41,12 +37,4 @@ class MainActivityViewModel(application: Application) : AndroidViewModel(applica
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MainActivityViewModelFactory(
|
||||
val application: Application,
|
||||
) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return modelClass.getConstructor(Application::class.java).newInstance(application)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,43 +1,28 @@
|
|||
package org.pixeldroid.app.postCreation
|
||||
|
||||
import android.os.*
|
||||
import android.os.Bundle
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import org.pixeldroid.app.R
|
||||
import org.pixeldroid.app.databinding.ActivityPostCreationBinding
|
||||
import org.pixeldroid.app.utils.BaseActivity
|
||||
import org.pixeldroid.app.utils.db.entities.InstanceDatabaseEntity
|
||||
import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity
|
||||
|
||||
const val TAG = "Post Creation Activity"
|
||||
|
||||
class PostCreationActivity : BaseActivity() {
|
||||
|
||||
companion object {
|
||||
internal const val PICTURE_DESCRIPTION = "picture_description"
|
||||
internal const val POST_DESCRIPTION = "post_description"
|
||||
internal const val PICTURE_DESCRIPTIONS = "picture_descriptions"
|
||||
internal const val POST_REDRAFT = "post_redraft"
|
||||
internal const val POST_NSFW = "post_nsfw"
|
||||
internal const val TEMP_FILES = "temp_files"
|
||||
}
|
||||
|
||||
private var user: UserDatabaseEntity? = null
|
||||
private lateinit var instance: InstanceDatabaseEntity
|
||||
|
||||
private lateinit var binding: ActivityPostCreationBinding
|
||||
|
||||
private lateinit var navController: NavController
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
user = db.userDao().getActiveUser()
|
||||
|
||||
instance = user?.run {
|
||||
db.instanceDao().getAll().first { instanceDatabaseEntity ->
|
||||
instanceDatabaseEntity.uri.contains(instance_uri)
|
||||
}
|
||||
} ?: InstanceDatabaseEntity("", "")
|
||||
|
||||
binding = ActivityPostCreationBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
val navHostFragment =
|
||||
|
@ -46,8 +31,5 @@ class PostCreationActivity : BaseActivity() {
|
|||
navController.setGraph(R.navigation.post_creation_graph)
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
return navController.navigateUp() || super.onSupportNavigateUp()
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp() = navController.navigateUp() || super.onSupportNavigateUp()
|
||||
}
|
|
@ -33,12 +33,10 @@ import kotlinx.coroutines.launch
|
|||
import org.pixeldroid.app.R
|
||||
import org.pixeldroid.app.databinding.FragmentPostCreationBinding
|
||||
import org.pixeldroid.app.postCreation.camera.CameraActivity
|
||||
import org.pixeldroid.app.postCreation.camera.CameraFragment
|
||||
import org.pixeldroid.app.postCreation.carousel.CarouselItem
|
||||
import org.pixeldroid.app.utils.BaseFragment
|
||||
import org.pixeldroid.app.utils.bindingLifecycleAware
|
||||
import org.pixeldroid.app.utils.db.entities.InstanceDatabaseEntity
|
||||
import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity
|
||||
import org.pixeldroid.app.utils.fileExtension
|
||||
import org.pixeldroid.app.utils.getMimeType
|
||||
import org.pixeldroid.media_editor.photoEdit.PhotoEditActivity
|
||||
|
@ -48,14 +46,10 @@ import java.io.OutputStream
|
|||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
|
||||
class PostCreationFragment : BaseFragment() {
|
||||
|
||||
private var user: UserDatabaseEntity? = null
|
||||
private var instance: InstanceDatabaseEntity = InstanceDatabaseEntity("", "")
|
||||
|
||||
private var binding: FragmentPostCreationBinding by bindingLifecycleAware()
|
||||
private lateinit var model: PostCreationViewModel
|
||||
private val model: PostCreationViewModel by activityViewModels()
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
|
@ -72,30 +66,16 @@ class PostCreationFragment : BaseFragment() {
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
user = db.userDao().getActiveUser()
|
||||
val user = db.userDao().getActiveUser()
|
||||
|
||||
instance = user?.run {
|
||||
db.instanceDao().getAll().first { instanceDatabaseEntity ->
|
||||
instanceDatabaseEntity.uri.contains(instance_uri)
|
||||
}
|
||||
val instance = user?.run {
|
||||
db.instanceDao().getInstance(instance_uri)
|
||||
} ?: InstanceDatabaseEntity("", "")
|
||||
|
||||
val _model: PostCreationViewModel by activityViewModels {
|
||||
PostCreationViewModelFactory(
|
||||
requireActivity().application,
|
||||
requireActivity().intent.clipData!!,
|
||||
instance,
|
||||
requireActivity().intent.getStringExtra(PostCreationActivity.PICTURE_DESCRIPTION),
|
||||
requireActivity().intent.getBooleanExtra(PostCreationActivity.POST_NSFW, false),
|
||||
requireActivity().intent.getBooleanExtra(CameraFragment.CAMERA_ACTIVITY_STORY, false),
|
||||
)
|
||||
}
|
||||
model = _model
|
||||
|
||||
model.getPhotoData().observe(viewLifecycleOwner) { newPhotoData ->
|
||||
model.getPhotoData().observe(viewLifecycleOwner) { newPhotoData: MutableList<PhotoData>? ->
|
||||
// update UI
|
||||
binding.carousel.addData(
|
||||
newPhotoData.map {
|
||||
newPhotoData.orEmpty().map {
|
||||
CarouselItem(
|
||||
it.imageUri, it.imageDescription, it.video,
|
||||
it.videoEncodeProgress, it.videoEncodeStabilizationFirstPass,
|
||||
|
@ -103,7 +83,7 @@ class PostCreationFragment : BaseFragment() {
|
|||
)
|
||||
}
|
||||
)
|
||||
binding.postCreationNextButton.isEnabled = newPhotoData.isNotEmpty()
|
||||
binding.postCreationNextButton.isEnabled = newPhotoData?.isNotEmpty() ?: false
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
|
@ -227,10 +207,9 @@ class PostCreationFragment : BaseFragment() {
|
|||
}
|
||||
|
||||
private val addPhotoResultContract = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK && result.data?.clipData != null) {
|
||||
result.data?.clipData?.let {
|
||||
model.setImages(model.addPossibleImages(it))
|
||||
}
|
||||
val uris = result.data?.extras?.getParcelableArrayList<Uri>(Intent.EXTRA_STREAM)
|
||||
if (result.resultCode == Activity.RESULT_OK && uris != null) {
|
||||
model.setImages(model.addPossibleImages(uris, emptyList()))
|
||||
} else if (result.resultCode != Activity.RESULT_CANCELED) {
|
||||
Toast.makeText(requireActivity(), R.string.add_images_error, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package org.pixeldroid.app.postCreation
|
||||
|
||||
import android.app.Application
|
||||
import android.content.ClipData
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Parcelable
|
||||
|
@ -12,15 +11,16 @@ import android.widget.Toast
|
|||
import androidx.core.net.toFile
|
||||
import androidx.core.net.toUri
|
||||
import androidx.exifinterface.media.ExifInterface
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.jarsilio.android.scrambler.exceptions.UnsupportedFileFormatException
|
||||
import com.jarsilio.android.scrambler.stripMetadata
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.core.Observable
|
||||
import io.reactivex.rxjava3.disposables.Disposable
|
||||
|
@ -33,10 +33,10 @@ import kotlinx.parcelize.Parcelize
|
|||
import okhttp3.MultipartBody
|
||||
import org.pixeldroid.app.MainActivity
|
||||
import org.pixeldroid.app.R
|
||||
import org.pixeldroid.app.utils.PixelDroidApplication
|
||||
import org.pixeldroid.app.utils.api.objects.Attachment
|
||||
import org.pixeldroid.app.utils.db.entities.InstanceDatabaseEntity
|
||||
import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity
|
||||
import org.pixeldroid.app.postCreation.camera.CameraFragment
|
||||
import org.pixeldroid.app.utils.api.objects.Attachment
|
||||
import org.pixeldroid.app.utils.db.AppDatabase
|
||||
import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity
|
||||
import org.pixeldroid.app.utils.di.PixelfedAPIHolder
|
||||
import org.pixeldroid.app.utils.fileExtension
|
||||
import org.pixeldroid.app.utils.getMimeType
|
||||
|
@ -47,21 +47,10 @@ import java.io.FileNotFoundException
|
|||
import java.io.IOException
|
||||
import java.net.URI
|
||||
import javax.inject.Inject
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.MutableList
|
||||
import kotlin.collections.MutableMap
|
||||
import kotlin.collections.arrayListOf
|
||||
import kotlin.collections.forEach
|
||||
import kotlin.collections.get
|
||||
import kotlin.collections.getOrNull
|
||||
import kotlin.collections.indexOfFirst
|
||||
import kotlin.collections.mutableListOf
|
||||
import kotlin.collections.mutableMapOf
|
||||
import kotlin.collections.plus
|
||||
import kotlin.collections.set
|
||||
import kotlin.collections.toMutableList
|
||||
import kotlin.math.ceil
|
||||
|
||||
const val TAG = "Post Creation ViewModel"
|
||||
|
||||
// Models the UI state for the PostCreationActivity
|
||||
data class PostCreationActivityUiState(
|
||||
|
@ -108,35 +97,40 @@ data class PhotoData(
|
|||
var videoEncodeError: Boolean = false,
|
||||
) : Parcelable
|
||||
|
||||
class PostCreationViewModel(
|
||||
application: Application,
|
||||
clipdata: ClipData? = null,
|
||||
val instance: InstanceDatabaseEntity? = null,
|
||||
existingDescription: String? = null,
|
||||
existingNSFW: Boolean = false,
|
||||
storyCreation: Boolean = false,
|
||||
) : AndroidViewModel(application) {
|
||||
@HiltViewModel
|
||||
class PostCreationViewModel @Inject constructor(
|
||||
private val state: SavedStateHandle,
|
||||
@ApplicationContext private val applicationContext: Context,
|
||||
db: AppDatabase
|
||||
): ViewModel() {
|
||||
private var storyPhotoDataBackup: MutableList<PhotoData>? = null
|
||||
private val photoData: MutableLiveData<MutableList<PhotoData>> by lazy {
|
||||
MutableLiveData<MutableList<PhotoData>>().also {
|
||||
it.value = clipdata?.let { it1 -> addPossibleImages(it1, mutableListOf()) }
|
||||
}
|
||||
MutableLiveData<MutableList<PhotoData>>(
|
||||
addPossibleImages(
|
||||
state.get<ArrayList<Uri>>(Intent.EXTRA_STREAM),
|
||||
state.get<ArrayList<String>>(PostCreationActivity.PICTURE_DESCRIPTIONS),
|
||||
mutableListOf()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private val instance = db.instanceDao().getActiveInstance()
|
||||
|
||||
@Inject
|
||||
lateinit var apiHolder: PixelfedAPIHolder
|
||||
|
||||
private val _uiState: MutableStateFlow<PostCreationActivityUiState>
|
||||
|
||||
init {
|
||||
(application as PixelDroidApplication).getAppComponent().inject(this)
|
||||
val sharedPreferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(application)
|
||||
PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
||||
val templateDescription = sharedPreferences.getString("prefill_description", "") ?: ""
|
||||
|
||||
val storyCreation: Boolean = state[CameraFragment.CAMERA_ACTIVITY_STORY] ?: false
|
||||
|
||||
_uiState = MutableStateFlow(PostCreationActivityUiState(
|
||||
newPostDescriptionText = existingDescription ?: templateDescription,
|
||||
nsfw = existingNSFW,
|
||||
newPostDescriptionText = state[PostCreationActivity.POST_DESCRIPTION] ?: templateDescription,
|
||||
nsfw = state[PostCreationActivity.POST_NSFW] ?: false,
|
||||
maxEntries = if(storyCreation) 1 else instance?.albumLimit,
|
||||
storyCreation = storyCreation
|
||||
))
|
||||
|
@ -161,32 +155,41 @@ class PostCreationViewModel(
|
|||
fun getPhotoData(): LiveData<MutableList<PhotoData>> = photoData
|
||||
|
||||
/**
|
||||
* Will add as many images as possible to [photoData], from the [clipData], and if
|
||||
* ([photoData].size + [clipData].itemCount) > uiState.value.maxEntries then it will only add as many images
|
||||
* Will add as many images as possible to [photoData], from the [uris], and if
|
||||
* ([photoData].size + [uris].size) > uiState.value.maxEntries then it will only add as many images
|
||||
* as are legal (if any) and a dialog will be shown to the user alerting them of this fact.
|
||||
*/
|
||||
fun addPossibleImages(clipData: ClipData, previousList: MutableList<PhotoData>? = photoData.value): MutableList<PhotoData> {
|
||||
fun addPossibleImages(
|
||||
uris: ArrayList<Uri>?,
|
||||
descriptions: List<String>?,
|
||||
previousList: MutableList<PhotoData>? = photoData.value,
|
||||
): MutableList<PhotoData> {
|
||||
val dataToAdd: ArrayList<PhotoData> = arrayListOf()
|
||||
var count = clipData.itemCount
|
||||
uiState.value.maxEntries?.let {
|
||||
if(count + (previousList?.size ?: 0) > it){
|
||||
var count = uris?.size ?: 0
|
||||
uiState.value.maxEntries?.let { maxEntries ->
|
||||
if(count + (previousList?.size ?: 0) > maxEntries){
|
||||
_uiState.update { currentUiState ->
|
||||
currentUiState.copy(userMessage = getApplication<PixelDroidApplication>().getString(R.string.total_exceeds_album_limit).format(it))
|
||||
currentUiState.copy(userMessage = applicationContext.getString(R.string.total_exceeds_album_limit).format(maxEntries))
|
||||
}
|
||||
count = count.coerceAtMost(it - (previousList?.size ?: 0))
|
||||
count = count.coerceAtMost(maxEntries - (previousList?.size ?: 0))
|
||||
}
|
||||
if (count + (previousList?.size ?: 0) >= it) {
|
||||
if (count + (previousList?.size ?: 0) >= maxEntries) {
|
||||
// Disable buttons to add more images
|
||||
_uiState.update { currentUiState ->
|
||||
currentUiState.copy(addPhotoButtonEnabled = false)
|
||||
}
|
||||
}
|
||||
for (i in 0 until count) {
|
||||
clipData.getItemAt(i).let {
|
||||
val sizeAndVideoPair: Pair<Long, Boolean> =
|
||||
getSizeAndVideoValidate(it.uri, (previousList?.size ?: 0) + dataToAdd.size + 1)
|
||||
dataToAdd.add(PhotoData(imageUri = it.uri, size = sizeAndVideoPair.first, video = sizeAndVideoPair.second, imageDescription = it.text?.toString()))
|
||||
}
|
||||
for ((i, uri) in uris.orEmpty().withIndex()) {
|
||||
val sizeAndVideoPair: Pair<Long, Boolean> =
|
||||
getSizeAndVideoValidate(uri, (previousList?.size ?: 0) + dataToAdd.size + 1)
|
||||
dataToAdd.add(
|
||||
PhotoData(
|
||||
imageUri = uri,
|
||||
size = sizeAndVideoPair.first,
|
||||
video = sizeAndVideoPair.second,
|
||||
imageDescription = descriptions?.getOrNull(i)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,7 +207,7 @@ class PostCreationViewModel(
|
|||
private fun getSizeAndVideoValidate(uri: Uri, editPosition: Int): Pair<Long, Boolean> {
|
||||
val size: Long =
|
||||
if (uri.scheme =="content") {
|
||||
getApplication<PixelDroidApplication>().contentResolver.query(uri, null, null, null, null)
|
||||
applicationContext.contentResolver.query(uri, null, null, null, null)
|
||||
?.use { cursor ->
|
||||
/* Get the column indexes of the data in the Cursor,
|
||||
* move to the first row in the Cursor, get the data,
|
||||
|
@ -221,12 +224,12 @@ class PostCreationViewModel(
|
|||
}
|
||||
|
||||
val sizeInkBytes = ceil(size.toDouble() / 1000).toLong()
|
||||
val type = uri.getMimeType(getApplication<PixelDroidApplication>().contentResolver)
|
||||
val type = uri.getMimeType(applicationContext.contentResolver)
|
||||
val isVideo = type.startsWith("video/")
|
||||
|
||||
if (isVideo && !instance!!.videoEnabled) {
|
||||
_uiState.update { currentUiState ->
|
||||
currentUiState.copy(userMessage = getApplication<PixelDroidApplication>().getString(R.string.video_not_supported))
|
||||
currentUiState.copy(userMessage = applicationContext.getString(R.string.video_not_supported))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -235,7 +238,7 @@ class PostCreationViewModel(
|
|||
val maxSize = if (isVideo) instance.maxVideoSize else instance.maxPhotoSize
|
||||
_uiState.update { currentUiState ->
|
||||
currentUiState.copy(
|
||||
userMessage = getApplication<PixelDroidApplication>().getString(R.string.size_exceeds_instance_limit, editPosition, sizeInkBytes, maxSize)
|
||||
userMessage = applicationContext.getString(R.string.size_exceeds_instance_limit, editPosition, sizeInkBytes, maxSize)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -272,7 +275,7 @@ class PostCreationViewModel(
|
|||
videoEncodeComplete = false
|
||||
|
||||
VideoEditActivity.startEncoding(imageUri, null, it,
|
||||
context = getApplication<PixelDroidApplication>(),
|
||||
context = applicationContext,
|
||||
registerNewFFmpegSession = ::registerNewFFmpegSession,
|
||||
trackTempFile = ::trackTempFile,
|
||||
videoEncodeProgress = ::videoEncodeProgress
|
||||
|
@ -387,17 +390,17 @@ class PostCreationViewModel(
|
|||
}
|
||||
|
||||
for (data: PhotoData in getPhotoData().value ?: emptyList()) {
|
||||
val extension = data.imageUri.fileExtension(getApplication<PixelDroidApplication>().contentResolver)
|
||||
val extension = data.imageUri.fileExtension(applicationContext.contentResolver)
|
||||
|
||||
val strippedImage = File.createTempFile("temp_img", ".$extension", getApplication<PixelDroidApplication>().cacheDir)
|
||||
val strippedImage = File.createTempFile("temp_img", ".$extension", applicationContext.cacheDir)
|
||||
|
||||
val imageUri = data.imageUri
|
||||
|
||||
val (strippedOrNot, size) = try {
|
||||
val orientation = ExifInterface(getApplication<PixelDroidApplication>().contentResolver.openInputStream(imageUri)!!).getAttributeInt(
|
||||
val orientation = ExifInterface(applicationContext.contentResolver.openInputStream(imageUri)!!).getAttributeInt(
|
||||
ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
|
||||
|
||||
stripMetadata(imageUri, strippedImage, getApplication<PixelDroidApplication>().contentResolver)
|
||||
stripMetadata(imageUri, strippedImage, applicationContext.contentResolver)
|
||||
|
||||
// Restore EXIF orientation
|
||||
val exifInterface = ExifInterface(strippedImage)
|
||||
|
@ -409,11 +412,11 @@ class PostCreationViewModel(
|
|||
strippedImage.delete()
|
||||
if(imageUri != data.imageUri) File(URI(imageUri.toString())).delete()
|
||||
val imageInputStream = try {
|
||||
getApplication<PixelDroidApplication>().contentResolver.openInputStream(imageUri)!!
|
||||
applicationContext.contentResolver.openInputStream(imageUri)!!
|
||||
} catch (e: FileNotFoundException){
|
||||
_uiState.update { currentUiState ->
|
||||
currentUiState.copy(
|
||||
userMessage = getApplication<PixelDroidApplication>().getString(R.string.file_not_found,
|
||||
userMessage = applicationContext.getString(R.string.file_not_found,
|
||||
data.imageUri)
|
||||
)
|
||||
}
|
||||
|
@ -425,14 +428,14 @@ class PostCreationViewModel(
|
|||
if(imageUri != data.imageUri) File(URI(imageUri.toString())).delete()
|
||||
_uiState.update { currentUiState ->
|
||||
currentUiState.copy(
|
||||
userMessage = getApplication<PixelDroidApplication>().getString(R.string.file_not_found,
|
||||
userMessage = applicationContext.getString(R.string.file_not_found,
|
||||
data.imageUri)
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
val type = data.imageUri.getMimeType(getApplication<PixelDroidApplication>().contentResolver)
|
||||
val type = data.imageUri.getMimeType(applicationContext.contentResolver)
|
||||
val imagePart = ProgressRequestBody(strippedOrNot, size, type)
|
||||
val requestBody = MultipartBody.Builder()
|
||||
.setType(MultipartBody.FORM)
|
||||
|
@ -482,7 +485,7 @@ class PostCreationViewModel(
|
|||
currentUiState.copy(
|
||||
uploadErrorVisible = true,
|
||||
uploadErrorExplanationText = if(e is HttpException){
|
||||
getApplication<PixelDroidApplication>().getString(R.string.upload_error, e.code())
|
||||
applicationContext.getString(R.string.upload_error, e.code())
|
||||
} else "",
|
||||
uploadErrorExplanationVisible = e is HttpException,
|
||||
)
|
||||
|
@ -548,14 +551,14 @@ class PostCreationViewModel(
|
|||
sensitive = nsfw
|
||||
)
|
||||
}
|
||||
Toast.makeText(getApplication(), getApplication<PixelDroidApplication>().getString(R.string.upload_post_success),
|
||||
Toast.makeText(applicationContext, applicationContext.getString(R.string.upload_post_success),
|
||||
Toast.LENGTH_SHORT).show()
|
||||
val intent = Intent(getApplication(), MainActivity::class.java)
|
||||
val intent = Intent(applicationContext, MainActivity::class.java)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
//TODO make the activity launch this instead (and surrounding toasts too)
|
||||
getApplication<PixelDroidApplication>().startActivity(intent)
|
||||
applicationContext.startActivity(intent)
|
||||
} catch (exception: IOException) {
|
||||
Toast.makeText(getApplication(), getApplication<PixelDroidApplication>().getString(R.string.upload_post_error),
|
||||
Toast.makeText(applicationContext, applicationContext.getString(R.string.upload_post_error),
|
||||
Toast.LENGTH_SHORT).show()
|
||||
Log.e(TAG, exception.toString())
|
||||
_uiState.update { currentUiState ->
|
||||
|
@ -564,7 +567,7 @@ class PostCreationViewModel(
|
|||
)
|
||||
}
|
||||
} catch (exception: HttpException) {
|
||||
Toast.makeText(getApplication(), getApplication<PixelDroidApplication>().getString(R.string.upload_post_failed),
|
||||
Toast.makeText(applicationContext, applicationContext.getString(R.string.upload_post_failed),
|
||||
Toast.LENGTH_SHORT).show()
|
||||
Log.e(TAG, exception.response().toString() + exception.message().toString())
|
||||
_uiState.update { currentUiState ->
|
||||
|
@ -609,7 +612,7 @@ class PostCreationViewModel(
|
|||
|
||||
//Show message saying extraneous pictures were removed but can be restored
|
||||
newUiState = newUiState.copy(
|
||||
userMessage = getApplication<PixelDroidApplication>().getString(R.string.extraneous_pictures_stories)
|
||||
userMessage = applicationContext.getString(R.string.extraneous_pictures_stories)
|
||||
)
|
||||
}
|
||||
// Restore if backup not null and first value is unchanged
|
||||
|
@ -629,10 +632,4 @@ class PostCreationViewModel(
|
|||
fun updateStoryReactions(checked: Boolean) { _uiState.update { it.copy(storyReactions = checked) } }
|
||||
|
||||
fun updateStoryReplies(checked: Boolean) { _uiState.update { it.copy(storyReplies = checked) } }
|
||||
}
|
||||
|
||||
class PostCreationViewModelFactory(val application: Application, val clipdata: ClipData, val instance: InstanceDatabaseEntity, val existingDescription: String?, val existingNSFW: Boolean, val storyCreation: Boolean) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return modelClass.getConstructor(Application::class.java, ClipData::class.java, InstanceDatabaseEntity::class.java, String::class.java, Boolean::class.java, Boolean::class.java).newInstance(application, clipdata, instance, existingDescription, existingNSFW, storyCreation)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,7 +38,7 @@ class PostSubmissionFragment : BaseFragment() {
|
|||
private lateinit var instance: InstanceDatabaseEntity
|
||||
|
||||
private var binding: FragmentPostSubmissionBinding by bindingLifecycleAware()
|
||||
private lateinit var model: PostCreationViewModel
|
||||
private val model: PostCreationViewModel by activityViewModels()
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
|
@ -60,23 +60,9 @@ class PostSubmissionFragment : BaseFragment() {
|
|||
accounts = db.userDao().getAll()
|
||||
|
||||
instance = user?.run {
|
||||
db.instanceDao().getAll().first { instanceDatabaseEntity ->
|
||||
instanceDatabaseEntity.uri.contains(instance_uri)
|
||||
}
|
||||
db.instanceDao().getInstance(instance_uri)
|
||||
} ?: InstanceDatabaseEntity("", "")
|
||||
|
||||
val _model: PostCreationViewModel by activityViewModels {
|
||||
PostCreationViewModelFactory(
|
||||
requireActivity().application,
|
||||
requireActivity().intent.clipData!!,
|
||||
instance,
|
||||
requireActivity().intent.getStringExtra(PostCreationActivity.PICTURE_DESCRIPTION),
|
||||
requireActivity().intent.getBooleanExtra(PostCreationActivity.POST_NSFW, false),
|
||||
requireActivity().intent.getBooleanExtra(CameraFragment.CAMERA_ACTIVITY_STORY, false)
|
||||
)
|
||||
}
|
||||
model = _model
|
||||
|
||||
// Display the values from the view model
|
||||
binding.nsfwSwitch.isChecked = model.uiState.value.nsfw
|
||||
binding.newPostDescriptionInputField.setText(model.uiState.value.newPostDescriptionText)
|
||||
|
|
|
@ -38,6 +38,7 @@ import kotlinx.coroutines.Dispatchers
|
|||
import kotlinx.coroutines.launch
|
||||
import org.pixeldroid.app.databinding.FragmentCameraBinding
|
||||
import org.pixeldroid.app.postCreation.PostCreationActivity
|
||||
import org.pixeldroid.app.posts.fromHtml
|
||||
import org.pixeldroid.app.utils.BaseFragment
|
||||
import java.io.File
|
||||
import java.util.concurrent.ExecutorService
|
||||
|
@ -326,7 +327,7 @@ class CameraFragment : BaseFragment() {
|
|||
}
|
||||
|
||||
private fun setupUploadImage() {
|
||||
val videoEnabled: Boolean = db.instanceDao().getInstance(db.userDao().getActiveUser()!!.instance_uri).videoEnabled
|
||||
val videoEnabled: Boolean = db.instanceDao().getActiveInstance().videoEnabled
|
||||
var mimeTypes: Array<String> = arrayOf("image/*")
|
||||
if(videoEnabled) mimeTypes += "video/*"
|
||||
|
||||
|
@ -449,21 +450,16 @@ class CameraFragment : BaseFragment() {
|
|||
|
||||
private fun startAlbumCreation(uris: ArrayList<String>) {
|
||||
|
||||
val intent = Intent(requireActivity(), PostCreationActivity::class.java)
|
||||
.apply {
|
||||
uris.forEach{
|
||||
//Why are we using ClipData here? Because the FLAG_GRANT_READ_URI_PERMISSION
|
||||
//needs to be applied to the URIs, and this flag only applies to the
|
||||
//Intent's data and any URIs specified in its ClipData.
|
||||
if(clipData == null){
|
||||
clipData = ClipData("", emptyArray(), ClipData.Item(it.toUri()))
|
||||
} else {
|
||||
clipData!!.addItem(ClipData.Item(it.toUri()))
|
||||
}
|
||||
}
|
||||
addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
}
|
||||
val intent = Intent(Intent.ACTION_SEND_MULTIPLE).apply {
|
||||
// Pass downloaded images to new post creation activity
|
||||
putParcelableArrayListExtra(
|
||||
Intent.EXTRA_STREAM, ArrayList(uris.map { it.toUri() })
|
||||
)
|
||||
setClass(requireContext(), PostCreationActivity::class.java)
|
||||
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
|
||||
}
|
||||
|
||||
if(inActivity && !addToStory){
|
||||
requireActivity().setResult(Activity.RESULT_OK, intent)
|
||||
|
|
|
@ -2,10 +2,8 @@ package org.pixeldroid.app.posts
|
|||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.ClipData
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager.PERMISSION_DENIED
|
||||
import android.content.pm.PackageManager.PERMISSION_GRANTED
|
||||
import android.graphics.Typeface
|
||||
import android.graphics.drawable.AnimatedVectorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
|
@ -77,7 +75,7 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold
|
|||
fun bind(
|
||||
status: Status?, pixelfedAPI: PixelfedAPIHolder, db: AppDatabase,
|
||||
lifecycleScope: LifecycleCoroutineScope, displayDimensionsInPx: Pair<Int, Int>,
|
||||
requestPermissionDownloadPic: ActivityResultLauncher<String>, isActivity: Boolean = false
|
||||
requestPermissionDownloadPic: ActivityResultLauncher<String>, isActivity: Boolean = false,
|
||||
) {
|
||||
|
||||
this.itemView.visibility = View.VISIBLE
|
||||
|
@ -371,7 +369,7 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold
|
|||
apiHolder: PixelfedAPIHolder,
|
||||
db: AppDatabase,
|
||||
lifecycleScope: LifecycleCoroutineScope,
|
||||
requestPermissionDownloadPic: ActivityResultLauncher<String>
|
||||
requestPermissionDownloadPic: ActivityResultLauncher<String>,
|
||||
){
|
||||
var bookmarked: Boolean? = null
|
||||
binding.statusMore.setOnClickListener {
|
||||
|
@ -449,178 +447,7 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold
|
|||
|
||||
true
|
||||
}
|
||||
R.id.post_more_menu_redraft -> {
|
||||
MaterialAlertDialogBuilder(binding.root.context).apply {
|
||||
setMessage(R.string.redraft_dialog_launch)
|
||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
// Create new post creation activity
|
||||
val intent =
|
||||
Intent(context, PostCreationActivity::class.java)
|
||||
|
||||
// Get descriptions and images from original post
|
||||
val postDescription = status?.content ?: ""
|
||||
val postAttachments =
|
||||
status?.media_attachments!! // Catch possible exception from !! (?)
|
||||
val postNSFW = status?.sensitive
|
||||
|
||||
val imageUriStrings = postAttachments.map { postAttachment ->
|
||||
postAttachment.url ?: ""
|
||||
}
|
||||
val imageNames = imageUriStrings.map { imageUriString ->
|
||||
Uri.parse(imageUriString).lastPathSegment.toString()
|
||||
}
|
||||
val downloadedFiles = imageNames.map { imageName ->
|
||||
File(context.cacheDir, imageName)
|
||||
}
|
||||
val imageUris = downloadedFiles.map { downloadedFile ->
|
||||
Uri.fromFile(downloadedFile)
|
||||
}
|
||||
val imageDescriptions = postAttachments.map { postAttachment ->
|
||||
fromHtml(postAttachment.description ?: "").toString()
|
||||
}
|
||||
val downloadRequests: List<Request> = imageUriStrings.map { imageUriString ->
|
||||
Request.Builder().url(imageUriString).build()
|
||||
}
|
||||
|
||||
val counter = AtomicInteger(0)
|
||||
|
||||
// Define callback function for after downloading the images
|
||||
fun continuation() {
|
||||
// Wait for all outstanding downloads to finish
|
||||
if (counter.incrementAndGet() == imageUris.size) {
|
||||
if (allFilesExist(imageNames)) {
|
||||
// Delete original post
|
||||
lifecycleScope.launch {
|
||||
deletePost(apiHolder.api ?: apiHolder.setToCurrentUser(), db)
|
||||
}
|
||||
|
||||
val counterInt = counter.get()
|
||||
Toast.makeText(
|
||||
binding.root.context,
|
||||
binding.root.context.resources.getQuantityString(
|
||||
R.plurals.items_load_success,
|
||||
counterInt,
|
||||
counterInt
|
||||
),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
// Pass downloaded images to new post creation activity
|
||||
intent.apply {
|
||||
imageUris.zip(imageDescriptions).map { (imageUri, imageDescription) ->
|
||||
ClipData.Item(imageDescription, null, imageUri)
|
||||
}.forEach { imageItem ->
|
||||
if (clipData == null) {
|
||||
clipData = ClipData(
|
||||
"",
|
||||
emptyArray(),
|
||||
imageItem
|
||||
)
|
||||
} else {
|
||||
clipData!!.addItem(imageItem)
|
||||
}
|
||||
}
|
||||
addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
}
|
||||
|
||||
// Pass post description of existing post to new post creation activity
|
||||
intent.putExtra(
|
||||
PostCreationActivity.PICTURE_DESCRIPTION,
|
||||
fromHtml(postDescription).toString()
|
||||
)
|
||||
if (imageNames.isNotEmpty()) {
|
||||
intent.putExtra(
|
||||
PostCreationActivity.TEMP_FILES,
|
||||
imageNames.toTypedArray()
|
||||
)
|
||||
}
|
||||
intent.putExtra(
|
||||
PostCreationActivity.POST_REDRAFT,
|
||||
true
|
||||
)
|
||||
intent.putExtra(
|
||||
PostCreationActivity.POST_NSFW,
|
||||
postNSFW
|
||||
)
|
||||
|
||||
// Launch post creation activity
|
||||
binding.root.context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!allFilesExist(imageNames)) {
|
||||
// Track download progress
|
||||
Toast.makeText(
|
||||
binding.root.context,
|
||||
binding.root.context.getString(R.string.image_download_downloading),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
|
||||
// Iterate through all pictures of the original post
|
||||
downloadRequests.zip(downloadedFiles).forEach { (downloadRequest, downloadedFile) ->
|
||||
// Check whether image is in cache directory already (maybe rather do so using Glide in the future?)
|
||||
if (!downloadedFile.exists()) {
|
||||
OkHttpClient().newCall(downloadRequest)
|
||||
.enqueue(object : Callback {
|
||||
override fun onFailure(
|
||||
call: Call,
|
||||
e: IOException
|
||||
) {
|
||||
Looper.prepare()
|
||||
downloadedFile.delete()
|
||||
Toast.makeText(
|
||||
binding.root.context,
|
||||
binding.root.context.getString(R.string.redraft_post_failed_io_except),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun onResponse(
|
||||
call: Call,
|
||||
response: Response
|
||||
) {
|
||||
val sink: BufferedSink =
|
||||
downloadedFile.sink().buffer()
|
||||
sink.writeAll(response.body!!.source())
|
||||
sink.close()
|
||||
Looper.prepare()
|
||||
continuation()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
continuation()
|
||||
}
|
||||
}
|
||||
} catch (exception: HttpException) {
|
||||
Toast.makeText(
|
||||
binding.root.context,
|
||||
binding.root.context.getString(
|
||||
R.string.redraft_post_failed_error,
|
||||
exception.code()
|
||||
),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
} catch (exception: IOException) {
|
||||
Toast.makeText(
|
||||
binding.root.context,
|
||||
binding.root.context.getString(R.string.redraft_post_failed_io_except),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||
show()
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
R.id.post_more_menu_redraft -> launchRedraftDialog(lifecycleScope, apiHolder, db)
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
@ -645,6 +472,176 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold
|
|||
}
|
||||
}
|
||||
|
||||
private fun launchRedraftDialog(
|
||||
lifecycleScope: LifecycleCoroutineScope,
|
||||
apiHolder: PixelfedAPIHolder,
|
||||
db: AppDatabase
|
||||
): Boolean {
|
||||
MaterialAlertDialogBuilder(binding.root.context).apply {
|
||||
setMessage(R.string.redraft_dialog_launch)
|
||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
// Get descriptions and images from original post
|
||||
val postDescription = status?.content ?: ""
|
||||
val postAttachments =
|
||||
status?.media_attachments!! // TODO Catch possible exception from !! (?)
|
||||
val postNSFW = status?.sensitive
|
||||
|
||||
val imageUriStrings = postAttachments.map { postAttachment ->
|
||||
postAttachment.url ?: ""
|
||||
}
|
||||
val imageNames = imageUriStrings.map { imageUriString ->
|
||||
Uri.parse(imageUriString).lastPathSegment.toString()
|
||||
}
|
||||
val downloadedFiles = imageNames.map { imageName ->
|
||||
File(context.cacheDir, imageName)
|
||||
}
|
||||
val imageDescriptions = postAttachments.map { postAttachment ->
|
||||
fromHtml(
|
||||
postAttachment.description ?: ""
|
||||
).toString()
|
||||
}
|
||||
val downloadRequests: List<Request> =
|
||||
imageUriStrings.map { imageUriString ->
|
||||
Request.Builder().url(imageUriString).build()
|
||||
}
|
||||
|
||||
val imageUris = downloadedFiles.map { downloadedFile ->
|
||||
Uri.fromFile(downloadedFile)
|
||||
}
|
||||
|
||||
val counter = AtomicInteger(0)
|
||||
|
||||
// Define callback function for after downloading the images
|
||||
fun continuation() {
|
||||
// Wait for all outstanding downloads to finish
|
||||
if (counter.incrementAndGet() == imageUris.size) {
|
||||
if (allFilesExist(imageNames)) {
|
||||
// Delete original post
|
||||
lifecycleScope.launch {
|
||||
deletePost(
|
||||
apiHolder.api ?: apiHolder.setToCurrentUser(), db
|
||||
)
|
||||
}
|
||||
|
||||
val counterInt = counter.get()
|
||||
Toast.makeText(
|
||||
binding.root.context,
|
||||
binding.root.context.resources.getQuantityString(
|
||||
R.plurals.items_load_success, counterInt, counterInt
|
||||
),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
|
||||
// Create new post creation activity
|
||||
|
||||
//TODO use this instead of clipdata (everywhere)
|
||||
val intent = Intent(Intent.ACTION_SEND_MULTIPLE).apply {
|
||||
// Pass downloaded images to new post creation activity
|
||||
putParcelableArrayListExtra(
|
||||
Intent.EXTRA_STREAM, ArrayList(imageUris)
|
||||
)
|
||||
setClass(context, PostCreationActivity::class.java)
|
||||
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
|
||||
|
||||
putExtra(
|
||||
PostCreationActivity.PICTURE_DESCRIPTIONS,
|
||||
ArrayList(imageDescriptions)
|
||||
)
|
||||
// Pass post description of existing post to new post creation activity
|
||||
putExtra(
|
||||
PostCreationActivity.POST_DESCRIPTION,
|
||||
fromHtml(postDescription).toString()
|
||||
)
|
||||
if (imageNames.isNotEmpty()) {
|
||||
putExtra(
|
||||
PostCreationActivity.TEMP_FILES,
|
||||
imageNames.toTypedArray()
|
||||
)
|
||||
}
|
||||
putExtra(PostCreationActivity.POST_REDRAFT, true)
|
||||
putExtra(PostCreationActivity.POST_NSFW, postNSFW)
|
||||
}
|
||||
|
||||
// Launch post creation activity
|
||||
binding.root.context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!allFilesExist(imageNames)) {
|
||||
// Track download progress
|
||||
Toast.makeText(
|
||||
binding.root.context,
|
||||
binding.root.context.getString(R.string.image_download_downloading),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
|
||||
// Iterate through all pictures of the original post
|
||||
downloadRequests.zip(downloadedFiles)
|
||||
.forEach { (downloadRequest, downloadedFile) ->
|
||||
// Check whether image is in cache directory already (maybe rather do so using Glide in the future?)
|
||||
if (!downloadedFile.exists()) {
|
||||
OkHttpClient().newCall(downloadRequest)
|
||||
.enqueue(object : Callback {
|
||||
override fun onFailure(
|
||||
call: Call,
|
||||
e: IOException,
|
||||
) {
|
||||
Looper.prepare()
|
||||
downloadedFile.delete()
|
||||
Toast.makeText(
|
||||
binding.root.context,
|
||||
binding.root.context.getString(
|
||||
R.string.redraft_post_failed_io_except
|
||||
),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun onResponse(
|
||||
call: Call,
|
||||
response: Response,
|
||||
) {
|
||||
val sink: BufferedSink =
|
||||
downloadedFile.sink().buffer()
|
||||
sink.writeAll(response.body!!.source())
|
||||
sink.close()
|
||||
Looper.prepare()
|
||||
continuation()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
continuation()
|
||||
}
|
||||
}
|
||||
} catch (exception: HttpException) {
|
||||
Toast.makeText(
|
||||
binding.root.context, binding.root.context.getString(
|
||||
R.string.redraft_post_failed_error, exception.code()
|
||||
), Toast.LENGTH_SHORT
|
||||
).show()
|
||||
} catch (exception: IOException) {
|
||||
Toast.makeText(
|
||||
binding.root.context,
|
||||
binding.root.context.getString(R.string.redraft_post_failed_io_except),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||
show()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun activateLiker(
|
||||
apiHolder: PixelfedAPIHolder,
|
||||
isLiked: Boolean,
|
||||
|
|
|
@ -16,18 +16,20 @@
|
|||
|
||||
package org.pixeldroid.app.posts.feeds.cachedFeeds
|
||||
|
||||
import androidx.paging.*
|
||||
import androidx.paging.ExperimentalPagingApi
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.RemoteMediator
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.pixeldroid.app.utils.api.objects.FeedContentDatabase
|
||||
import org.pixeldroid.app.utils.db.AppDatabase
|
||||
import org.pixeldroid.app.utils.db.dao.feedContent.FeedContentDao
|
||||
import org.pixeldroid.app.utils.api.objects.FeedContentDatabase
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Repository class that works with local and remote data sources.
|
||||
*/
|
||||
class FeedContentRepository<T: FeedContentDatabase> @ExperimentalPagingApi
|
||||
@Inject constructor(
|
||||
class FeedContentRepository<T: FeedContentDatabase> @ExperimentalPagingApi constructor(
|
||||
private val db: AppDatabase,
|
||||
private val dao: FeedContentDao<T>,
|
||||
private val mediator: RemoteMediator<Int, T>
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package org.pixeldroid.app.posts.feeds.cachedFeeds.postFeeds
|
||||
|
||||
import androidx.paging.*
|
||||
import androidx.paging.ExperimentalPagingApi
|
||||
import androidx.paging.LoadType
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingState
|
||||
import androidx.paging.RemoteMediator
|
||||
import androidx.room.withTransaction
|
||||
import org.pixeldroid.app.utils.db.AppDatabase
|
||||
import org.pixeldroid.app.utils.di.PixelfedAPIHolder
|
||||
import org.pixeldroid.app.utils.db.entities.HomeStatusDatabaseEntity
|
||||
import java.lang.NullPointerException
|
||||
import javax.inject.Inject
|
||||
import org.pixeldroid.app.utils.di.PixelfedAPIHolder
|
||||
|
||||
|
||||
/**
|
||||
|
@ -17,7 +19,7 @@ import javax.inject.Inject
|
|||
* a local db cache.
|
||||
*/
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
class HomeFeedRemoteMediator @Inject constructor(
|
||||
class HomeFeedRemoteMediator(
|
||||
private val apiHolder: PixelfedAPIHolder,
|
||||
private val db: AppDatabase,
|
||||
) : RemoteMediator<Int, HomeStatusDatabaseEntity>() {
|
||||
|
|
|
@ -16,13 +16,15 @@
|
|||
|
||||
package org.pixeldroid.app.posts.feeds.cachedFeeds.postFeeds
|
||||
|
||||
import androidx.paging.*
|
||||
import androidx.paging.ExperimentalPagingApi
|
||||
import androidx.paging.LoadType
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingState
|
||||
import androidx.paging.RemoteMediator
|
||||
import androidx.room.withTransaction
|
||||
import org.pixeldroid.app.utils.db.AppDatabase
|
||||
import org.pixeldroid.app.utils.db.entities.PublicFeedStatusDatabaseEntity
|
||||
import org.pixeldroid.app.utils.di.PixelfedAPIHolder
|
||||
import java.lang.NullPointerException
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* RemoteMediator for the public feed.
|
||||
|
@ -32,7 +34,7 @@ import javax.inject.Inject
|
|||
* a local db cache.
|
||||
*/
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
class PublicFeedRemoteMediator @Inject constructor(
|
||||
class PublicFeedRemoteMediator(
|
||||
private val apiHolder: PixelfedAPIHolder,
|
||||
private val db: AppDatabase
|
||||
) : RemoteMediator<Int, PublicFeedStatusDatabaseEntity>() {
|
||||
|
|
|
@ -25,7 +25,7 @@ import org.pixeldroid.app.utils.openUrl
|
|||
|
||||
class EditProfileActivity : BaseActivity() {
|
||||
|
||||
private lateinit var model: EditProfileViewModel
|
||||
private val model: EditProfileViewModel by viewModels()
|
||||
private lateinit var binding: ActivityEditProfileBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
@ -35,9 +35,6 @@ class EditProfileActivity : BaseActivity() {
|
|||
setSupportActionBar(binding.topBar)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
|
||||
val _model: EditProfileViewModel by viewModels { EditProfileViewModelFactory(application) }
|
||||
model = _model
|
||||
|
||||
onBackPressedDispatcher.addCallback(this) {
|
||||
// Handle the back button event
|
||||
if(model.madeChanges()){
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
package org.pixeldroid.app.profile
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.provider.OpenableColumns
|
||||
import android.text.Editable
|
||||
import android.util.Log
|
||||
import androidx.core.net.toFile
|
||||
import androidx.core.net.toUri
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.disposables.Disposable
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
|
@ -21,7 +21,6 @@ import kotlinx.coroutines.launch
|
|||
import okhttp3.MultipartBody
|
||||
import org.pixeldroid.app.postCreation.ProgressRequestBody
|
||||
import org.pixeldroid.app.posts.fromHtml
|
||||
import org.pixeldroid.app.utils.PixelDroidApplication
|
||||
import org.pixeldroid.app.utils.api.objects.Account
|
||||
import org.pixeldroid.app.utils.db.AppDatabase
|
||||
import org.pixeldroid.app.utils.db.updateUserInfoDb
|
||||
|
@ -29,7 +28,10 @@ import org.pixeldroid.app.utils.di.PixelfedAPIHolder
|
|||
import retrofit2.HttpException
|
||||
import javax.inject.Inject
|
||||
|
||||
class EditProfileViewModel(application: Application) : AndroidViewModel(application) {
|
||||
@HiltViewModel
|
||||
class EditProfileViewModel @Inject constructor(
|
||||
@ApplicationContext private val applicationContext: Context
|
||||
): ViewModel() {
|
||||
|
||||
@Inject
|
||||
lateinit var apiHolder: PixelfedAPIHolder
|
||||
|
@ -46,7 +48,6 @@ class EditProfileViewModel(application: Application) : AndroidViewModel(applicat
|
|||
private set
|
||||
|
||||
init {
|
||||
(application as PixelDroidApplication).getAppComponent().inject(this)
|
||||
loadProfile()
|
||||
}
|
||||
|
||||
|
@ -197,12 +198,12 @@ class EditProfileViewModel(application: Application) : AndroidViewModel(applicat
|
|||
val image = uiState.value.profilePictureUri!!
|
||||
|
||||
val inputStream =
|
||||
getApplication<PixelDroidApplication>().contentResolver.openInputStream(image)
|
||||
applicationContext.contentResolver.openInputStream(image)
|
||||
?: return
|
||||
|
||||
val size: Long =
|
||||
if (image.scheme == "content") {
|
||||
getApplication<PixelDroidApplication>().contentResolver.query(
|
||||
applicationContext.contentResolver.query(
|
||||
image,
|
||||
null,
|
||||
null,
|
||||
|
@ -303,10 +304,4 @@ data class EditProfileActivityUiState(
|
|||
val error: Boolean = false,
|
||||
val uploadingPicture: Boolean = false,
|
||||
val uploadProgress: Int = 0,
|
||||
)
|
||||
|
||||
class EditProfileViewModelFactory(val application: Application) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return modelClass.getConstructor(Application::class.java).newInstance(application)
|
||||
}
|
||||
}
|
||||
)
|
|
@ -25,9 +25,6 @@ import org.pixeldroid.app.databinding.ActivityStoriesBinding
|
|||
import org.pixeldroid.app.posts.setTextViewFromISO8601
|
||||
import org.pixeldroid.app.utils.BaseActivity
|
||||
import org.pixeldroid.app.utils.api.objects.Account
|
||||
import org.pixeldroid.app.utils.api.objects.Story
|
||||
import org.pixeldroid.app.utils.api.objects.StoryCarousel
|
||||
|
||||
|
||||
class StoriesActivity: BaseActivity() {
|
||||
|
||||
|
@ -37,12 +34,11 @@ class StoriesActivity: BaseActivity() {
|
|||
const val STORY_CAROUSEL_USER_ID = "LaunchStoryUserId"
|
||||
}
|
||||
|
||||
|
||||
private lateinit var binding: ActivityStoriesBinding
|
||||
|
||||
private lateinit var storyProgress: StoryProgress
|
||||
|
||||
private lateinit var model: StoriesViewModel
|
||||
private val model: StoriesViewModel by viewModels()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
//force night mode always
|
||||
|
@ -50,18 +46,9 @@ class StoriesActivity: BaseActivity() {
|
|||
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val carousel = intent.getSerializableExtra(STORY_CAROUSEL) as? StoryCarousel
|
||||
val userId = intent.getStringExtra(STORY_CAROUSEL_USER_ID)
|
||||
val selfCarousel: Array<Story>? = intent.getSerializableExtra(STORY_CAROUSEL_SELF) as? Array<Story>
|
||||
|
||||
binding = ActivityStoriesBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
val _model: StoriesViewModel by viewModels {
|
||||
StoriesViewModelFactory(application, carousel, userId, selfCarousel?.asList())
|
||||
}
|
||||
model = _model
|
||||
|
||||
storyProgress = StoryProgress(model.uiState.value.imageList.size)
|
||||
binding.storyProgressImage.setImageDrawable(storyProgress)
|
||||
|
||||
|
|
|
@ -1,20 +1,18 @@
|
|||
package org.pixeldroid.app.stories
|
||||
|
||||
import android.app.Application
|
||||
import android.os.CountDownTimer
|
||||
import android.text.Editable
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import org.pixeldroid.app.R
|
||||
import org.pixeldroid.app.utils.PixelDroidApplication
|
||||
import org.pixeldroid.app.utils.api.objects.CarouselUserContainer
|
||||
import org.pixeldroid.app.utils.api.objects.Story
|
||||
import org.pixeldroid.app.utils.api.objects.StoryCarousel
|
||||
|
@ -37,18 +35,13 @@ data class StoriesUiState(
|
|||
val snackBar: Int? = null,
|
||||
val reply: String = ""
|
||||
)
|
||||
|
||||
class StoriesViewModel(
|
||||
application: Application,
|
||||
val carousel: StoryCarousel?,
|
||||
userId: String?,
|
||||
val selfCarousel: List<Story>?
|
||||
) : AndroidViewModel(application) {
|
||||
|
||||
@Inject
|
||||
lateinit var apiHolder: PixelfedAPIHolder
|
||||
@Inject
|
||||
lateinit var db: AppDatabase
|
||||
@HiltViewModel
|
||||
class StoriesViewModel @Inject constructor(state: SavedStateHandle,
|
||||
db: AppDatabase,
|
||||
private val apiHolder: PixelfedAPIHolder) : ViewModel() {
|
||||
private val carousel: StoryCarousel? = state[StoriesActivity.STORY_CAROUSEL]
|
||||
private val userId: String? = state[StoriesActivity.STORY_CAROUSEL_USER_ID]
|
||||
private val selfCarousel: Array<Story>? = state[StoriesActivity.STORY_CAROUSEL_SELF]
|
||||
|
||||
private var currentAccount: CarouselUserContainer?
|
||||
|
||||
|
@ -61,10 +54,9 @@ class StoriesViewModel(
|
|||
private var timer: CountDownTimer? = null
|
||||
|
||||
init {
|
||||
(application as PixelDroidApplication).getAppComponent().inject(this)
|
||||
currentAccount =
|
||||
if (selfCarousel != null) {
|
||||
db.userDao().getActiveUser()?.let { CarouselUserContainer(it, selfCarousel) }
|
||||
db.userDao().getActiveUser()?.let { CarouselUserContainer(it, selfCarousel.toList()) }
|
||||
} else carousel?.nodes?.firstOrNull { it?.user?.id == userId }
|
||||
|
||||
_uiState = MutableStateFlow(newUiStateFromCurrentAccount())
|
||||
|
@ -216,14 +208,3 @@ class StoriesViewModel(
|
|||
fun currentProfileId(): String? = currentAccount?.user?.id
|
||||
|
||||
}
|
||||
|
||||
class StoriesViewModelFactory(
|
||||
val application: Application,
|
||||
val carousel: StoryCarousel?,
|
||||
val userId: String?,
|
||||
val selfCarousel: List<Story>?
|
||||
) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return modelClass.getConstructor(Application::class.java, StoryCarousel::class.java, String::class.java, List::class.java).newInstance(application, carousel, userId, selfCarousel)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
package org.pixeldroid.app.utils
|
||||
|
||||
import android.os.Bundle
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.pixeldroid.app.utils.db.AppDatabase
|
||||
import org.pixeldroid.app.utils.di.PixelfedAPIHolder
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
open class BaseActivity : org.pixeldroid.common.ThemedActivity() {
|
||||
|
||||
@Inject
|
||||
|
@ -12,11 +13,6 @@ open class BaseActivity : org.pixeldroid.common.ThemedActivity() {
|
|||
@Inject
|
||||
lateinit var apiHolder: PixelfedAPIHolder
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
(this.application as PixelDroidApplication).getAppComponent().inject(this)
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
return true
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package org.pixeldroid.app.utils
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.pixeldroid.app.R
|
||||
import org.pixeldroid.app.utils.db.AppDatabase
|
||||
import org.pixeldroid.app.utils.di.PixelfedAPIHolder
|
||||
|
@ -12,6 +12,7 @@ import javax.inject.Inject
|
|||
/**
|
||||
* Base Fragment, for dependency injection and other things common to a lot of the fragments
|
||||
*/
|
||||
@AndroidEntryPoint
|
||||
open class BaseFragment: Fragment() {
|
||||
|
||||
@Inject
|
||||
|
@ -20,11 +21,6 @@ open class BaseFragment: Fragment() {
|
|||
@Inject
|
||||
lateinit var db: AppDatabase
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
(requireActivity().application as PixelDroidApplication).getAppComponent().inject(this)
|
||||
}
|
||||
|
||||
internal val requestPermissionDownloadPic =
|
||||
registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
|
|
|
@ -3,14 +3,12 @@ package org.pixeldroid.app.utils
|
|||
import android.app.Application
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.google.android.material.color.DynamicColors
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
import org.ligi.tracedroid.TraceDroid
|
||||
import org.pixeldroid.app.utils.di.*
|
||||
|
||||
|
||||
@HiltAndroidApp
|
||||
class PixelDroidApplication: Application() {
|
||||
|
||||
private lateinit var mApplicationComponent: ApplicationComponent
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
|
@ -19,18 +17,7 @@ class PixelDroidApplication: Application() {
|
|||
val sharedPreferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(this)
|
||||
setThemeFromPreferences(sharedPreferences, resources)
|
||||
mApplicationComponent = DaggerApplicationComponent
|
||||
.builder()
|
||||
.applicationModule(ApplicationModule(this))
|
||||
.databaseModule(DatabaseModule(applicationContext))
|
||||
.aPIModule(APIModule())
|
||||
.build()
|
||||
mApplicationComponent.inject(this)
|
||||
|
||||
DynamicColors.applyToActivitiesIfAvailable(this)
|
||||
}
|
||||
|
||||
fun getAppComponent(): ApplicationComponent {
|
||||
return mApplicationComponent
|
||||
}
|
||||
}
|
|
@ -44,7 +44,7 @@ suspend fun updateUserInfoDb(db: AppDatabase, account: Account) {
|
|||
)
|
||||
}
|
||||
|
||||
fun storeInstance(db: AppDatabase, nodeInfo: NodeInfo?, instance: Instance? = null) {
|
||||
suspend fun storeInstance(db: AppDatabase, nodeInfo: NodeInfo?, instance: Instance? = null) {
|
||||
val dbInstance: InstanceDatabaseEntity = nodeInfo?.run {
|
||||
InstanceDatabaseEntity(
|
||||
uri = normalizeDomain(metadata?.config?.site?.url!!),
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
package org.pixeldroid.app.utils.db.dao
|
||||
|
||||
import androidx.room.*
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import androidx.room.Update
|
||||
import org.pixeldroid.app.utils.db.entities.InstanceDatabaseEntity
|
||||
|
||||
@Dao
|
||||
interface InstanceDao {
|
||||
@Query("SELECT * FROM instances")
|
||||
fun getAll(): List<InstanceDatabaseEntity>
|
||||
|
||||
@Query("SELECT * FROM instances WHERE uri=:instanceUri")
|
||||
fun getInstance(instanceUri: String): InstanceDatabaseEntity
|
||||
|
||||
|
@ -19,13 +21,13 @@ interface InstanceDao {
|
|||
* Insert an instance, if it already exists return -1
|
||||
*/
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
fun insertInstance(instance: InstanceDatabaseEntity): Long
|
||||
suspend fun insertInstance(instance: InstanceDatabaseEntity): Long
|
||||
|
||||
@Update
|
||||
fun updateInstance(instance: InstanceDatabaseEntity)
|
||||
suspend fun updateInstance(instance: InstanceDatabaseEntity)
|
||||
|
||||
@Transaction
|
||||
fun insertOrUpdate(instance: InstanceDatabaseEntity) {
|
||||
suspend fun insertOrUpdate(instance: InstanceDatabaseEntity) {
|
||||
if (insertInstance(instance) == -1L) {
|
||||
updateInstance(instance)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
package org.pixeldroid.app.utils.db.dao
|
||||
|
||||
import androidx.room.*
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import androidx.room.Update
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity
|
||||
|
||||
|
|
|
@ -6,13 +6,16 @@ import org.pixeldroid.app.utils.db.AppDatabase
|
|||
import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import okhttp3.*
|
||||
import org.pixeldroid.app.utils.api.PixelfedAPI.Companion.apiForUser
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
class APIModule{
|
||||
@InstallIn(SingletonComponent::class)
|
||||
class APIModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
|
@ -54,7 +57,7 @@ class TokenAuthenticator(val user: UserDatabaseEntity, val db: AppDatabase, val
|
|||
client_secret = user.clientSecret
|
||||
)
|
||||
}
|
||||
}catch (e: Exception){
|
||||
} catch (e: Exception){
|
||||
return null
|
||||
}
|
||||
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
package org.pixeldroid.app.utils.di
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import org.pixeldroid.app.utils.BaseActivity
|
||||
import org.pixeldroid.app.utils.PixelDroidApplication
|
||||
import org.pixeldroid.app.utils.db.AppDatabase
|
||||
import org.pixeldroid.app.utils.BaseFragment
|
||||
import dagger.Component
|
||||
import org.pixeldroid.app.MainActivityViewModel
|
||||
import org.pixeldroid.app.postCreation.PostCreationViewModel
|
||||
import org.pixeldroid.app.profile.EditProfileViewModel
|
||||
import org.pixeldroid.app.stories.StoriesViewModel
|
||||
import org.pixeldroid.app.stories.StoryCarouselViewHolder
|
||||
import org.pixeldroid.app.utils.notificationsWorker.NotificationsWorker
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
||||
@Singleton
|
||||
@Component(modules = [ApplicationModule::class, DatabaseModule::class, APIModule::class])
|
||||
interface ApplicationComponent {
|
||||
fun inject(application: PixelDroidApplication?)
|
||||
fun inject(activity: BaseActivity?)
|
||||
fun inject(feedFragment: BaseFragment)
|
||||
fun inject(notificationsWorker: NotificationsWorker)
|
||||
fun inject(postCreationViewModel: PostCreationViewModel)
|
||||
fun inject(editProfileViewModel: EditProfileViewModel)
|
||||
fun inject(storiesViewModel: StoriesViewModel)
|
||||
fun inject(mainActivityViewModel: MainActivityViewModel)
|
||||
|
||||
val context: Context?
|
||||
val application: Application?
|
||||
val database: AppDatabase
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
package org.pixeldroid.app.utils.di
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
||||
@Module
|
||||
class ApplicationModule(app: Application) {
|
||||
private val mApplication: Application = app
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideContext(): Context {
|
||||
return mApplication
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideApplication(): Application {
|
||||
return mApplication
|
||||
}
|
||||
|
||||
}
|
|
@ -5,19 +5,25 @@ import androidx.room.Room
|
|||
import org.pixeldroid.app.utils.db.AppDatabase
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import org.pixeldroid.app.utils.db.MIGRATION_3_4
|
||||
import org.pixeldroid.app.utils.db.MIGRATION_4_5
|
||||
import org.pixeldroid.app.utils.db.MIGRATION_5_6
|
||||
import javax.inject.Singleton
|
||||
|
||||
@InstallIn(SingletonComponent::class)
|
||||
@Module
|
||||
class DatabaseModule(private val context: Context) {
|
||||
class DatabaseModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesDatabase(): AppDatabase {
|
||||
fun providesDatabase(
|
||||
@ApplicationContext applicationContext: Context
|
||||
): AppDatabase {
|
||||
return Room.databaseBuilder(
|
||||
context,
|
||||
applicationContext,
|
||||
AppDatabase::class.java, "pixeldroid"
|
||||
).addMigrations(MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6)
|
||||
.allowMainThreadQueries().build()
|
||||
|
|
|
@ -32,9 +32,6 @@ import java.io.IOException
|
|||
import java.time.Instant
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
|
||||
|
||||
class NotificationsWorker(
|
||||
context: Context,
|
||||
params: WorkerParameters
|
||||
|
@ -46,9 +43,6 @@ class NotificationsWorker(
|
|||
lateinit var apiHolder: PixelfedAPIHolder
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
|
||||
(applicationContext as PixelDroidApplication).getAppComponent().inject(this)
|
||||
|
||||
val users: List<UserDatabaseEntity> = db.userDao().getAll()
|
||||
|
||||
for (user in users){
|
||||
|
@ -306,8 +300,7 @@ fun removeNotificationChannelsFromAccount(context: Context, user: UserDatabaseEn
|
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
notificationManager.deleteNotificationChannelGroup(channelGroupId.hashCode().toString())
|
||||
} else {
|
||||
val types: MutableList<Notification.NotificationType?> =
|
||||
Notification.NotificationType.values().toMutableList()
|
||||
val types: MutableList<Notification.NotificationType?> = entries.toMutableList()
|
||||
types += null
|
||||
|
||||
types.forEach {
|
||||
|
|
|
@ -6,7 +6,7 @@ buildscript {
|
|||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.2.1'
|
||||
classpath 'com.android.tools.build:gradle:8.2.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
@ -16,6 +16,7 @@ buildscript {
|
|||
|
||||
plugins {
|
||||
id 'com.google.devtools.ksp' version '1.9.20-1.0.14' apply false
|
||||
id("com.google.dagger.hilt.android") version "2.50" apply false
|
||||
}
|
||||
|
||||
allprojects {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#Fri Oct 14 13:37:44 GMT 2022
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=38f66cd6eef217b4c35855bb11ea4e9fbc53594ccccb5fb82dfd317ef8c2c5a3
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
|
||||
distributionSha256Sum=3e1af3ae886920c3ac87f7a91f816c0c7c436f276a6eefdb3da152100fef72ae
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
Loading…
Reference in New Issue