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