WIP
This commit is contained in:
parent
7f2e16c580
commit
a32757c518
@ -19,6 +19,14 @@ android {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
compose true
|
||||
}
|
||||
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion = "1.5.2"
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.isolaatti"
|
||||
minSdk 24
|
||||
@ -137,4 +145,19 @@ dependencies {
|
||||
|
||||
// OSS screen
|
||||
implementation 'com.google.android.gms:play-services-oss-licenses:17.1.0'
|
||||
|
||||
def composeBom = platform('androidx.compose:compose-bom:2024.10.01')
|
||||
implementation composeBom
|
||||
androidTestImplementation composeBom
|
||||
implementation 'androidx.compose.material3:material3'
|
||||
implementation 'androidx.compose.ui:ui-tooling-preview'
|
||||
debugImplementation 'androidx.compose.ui:ui-tooling'
|
||||
androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
|
||||
debugImplementation 'androidx.compose.ui:ui-test-manifest'
|
||||
|
||||
implementation 'androidx.activity:activity-compose:1.9.2'
|
||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5'
|
||||
implementation 'androidx.compose.runtime:runtime-livedata'
|
||||
|
||||
implementation "io.coil-kt.coil3:coil-compose:3.0.1"
|
||||
}
|
||||
27
app/src/main/java/com/isolaatti/common/IsolaattiTheme.kt
Normal file
27
app/src/main/java/com/isolaatti/common/IsolaattiTheme.kt
Normal file
@ -0,0 +1,27 @@
|
||||
package com.isolaatti.common
|
||||
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import com.isolaatti.R
|
||||
|
||||
@Composable
|
||||
fun IsolaattiTheme(content: @Composable () -> Unit) {
|
||||
val colorScheme = if(isSystemInDarkTheme()) {
|
||||
darkColorScheme(
|
||||
primary = colorResource(R.color.purple),
|
||||
onSurface = colorResource(R.color.on_surface)
|
||||
)
|
||||
} else {
|
||||
lightColorScheme(
|
||||
primary = colorResource(R.color.purple),
|
||||
onSurface = colorResource(R.color.on_surface)
|
||||
)
|
||||
}
|
||||
MaterialTheme(colorScheme = colorScheme) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,10 @@
|
||||
package com.isolaatti.images
|
||||
|
||||
import android.app.Application
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import com.isolaatti.MyApplication
|
||||
import com.isolaatti.connectivity.RetrofitClient
|
||||
import com.isolaatti.database.AppDatabase
|
||||
import com.isolaatti.images.common.data.dao.ImagesDraftsDao
|
||||
import com.isolaatti.images.common.data.remote.ImagesApi
|
||||
import com.isolaatti.images.common.data.repository.ImagesRepositoryImpl
|
||||
import com.isolaatti.images.common.domain.repository.ImagesRepository
|
||||
@ -28,7 +28,12 @@ class Module {
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideImagesRepository(imagesApi: ImagesApi, contentResolver: ContentResolver): ImagesRepository {
|
||||
return ImagesRepositoryImpl(imagesApi, contentResolver)
|
||||
fun provideImagesDraftDao(database: AppDatabase): ImagesDraftsDao {
|
||||
return database.imagesDraftsDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideImagesRepository(imagesApi: ImagesApi, imagesDraftsDao: ImagesDraftsDao, contentResolver: ContentResolver): ImagesRepository {
|
||||
return ImagesRepositoryImpl(imagesApi, imagesDraftsDao, contentResolver)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,122 @@
|
||||
package com.isolaatti.images.common.components
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.FilledIconButton
|
||||
import androidx.compose.material3.FilledTonalIconButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Devices
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Popup
|
||||
import androidx.compose.ui.zIndex
|
||||
import coil3.compose.AsyncImage
|
||||
import com.isolaatti.R
|
||||
import com.isolaatti.images.common.domain.entity.Image
|
||||
|
||||
@Composable
|
||||
fun ImagesRow(
|
||||
modifier: Modifier = Modifier,
|
||||
images: List<Uri>,
|
||||
deletable: Boolean,
|
||||
addable: Boolean,
|
||||
onClick: (index: Int) -> Unit,
|
||||
onDeleteClick: (index: Int) -> Unit = {},
|
||||
onTakePicture: () -> Unit = {},
|
||||
onUploadPicture: () -> Unit = {}
|
||||
) {
|
||||
var showAddPhotoPopUp by remember { mutableStateOf(false) }
|
||||
LazyRow(modifier, contentPadding = PaddingValues(horizontal = 8.dp)) {
|
||||
if(addable) {
|
||||
item {
|
||||
Card(modifier = Modifier
|
||||
.padding(horizontal = 4.dp)
|
||||
.size(120.dp), onClick = {
|
||||
showAddPhotoPopUp = true
|
||||
}) {
|
||||
|
||||
|
||||
DropdownMenu(expanded = showAddPhotoPopUp, onDismissRequest = { showAddPhotoPopUp = false }) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.take_a_photo )) },
|
||||
onClick = {
|
||||
showAddPhotoPopUp = false
|
||||
onTakePicture()
|
||||
}
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.upload_a_picture )) },
|
||||
onClick = {
|
||||
showAddPhotoPopUp = false
|
||||
onUploadPicture()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Image(modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(16.dp),
|
||||
painter = painterResource(id = R.drawable.baseline_add_a_photo_24),
|
||||
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurface),
|
||||
contentDescription = null)
|
||||
}
|
||||
}
|
||||
}
|
||||
items(count = images.size) { index ->
|
||||
|
||||
Card(modifier = Modifier
|
||||
.padding(horizontal = 4.dp)
|
||||
.size(120.dp)) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
|
||||
) {
|
||||
FilledTonalIconButton(
|
||||
onClick = { onDeleteClick(index) },
|
||||
modifier = Modifier.zIndex(2f)
|
||||
) {
|
||||
Icon(imageVector = Icons.Default.Close, contentDescription = null)
|
||||
}
|
||||
|
||||
AsyncImage(
|
||||
model = images[index],
|
||||
contentDescription = null,
|
||||
modifier = Modifier.fillMaxSize().zIndex(1f),
|
||||
contentScale = ContentScale.Crop
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(device = Devices.PIXEL_5)
|
||||
@Composable
|
||||
fun ImagesRowPreview() {
|
||||
ImagesRow(images = emptyList(), deletable = false, addable = true, onClick = {})
|
||||
}
|
||||
@ -2,6 +2,7 @@ package com.isolaatti.images.common.data.entity
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import java.io.Serializable
|
||||
|
||||
@Entity(tableName = "image_drafts")
|
||||
data class ImageDraftEntity(
|
||||
@ -9,4 +10,4 @@ data class ImageDraftEntity(
|
||||
val id: Long,
|
||||
val uri: String,
|
||||
val postId: Long? = null
|
||||
)
|
||||
) : Serializable
|
||||
|
||||
@ -3,7 +3,6 @@ package com.isolaatti.images.common.data.remote
|
||||
data class ImageDto(
|
||||
val id: String,
|
||||
val userId: Int,
|
||||
val name: String,
|
||||
val squadId: String?,
|
||||
val username: String,
|
||||
val idOnFirebase: String
|
||||
|
||||
@ -6,6 +6,8 @@ import android.graphics.BitmapFactory
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import com.isolaatti.images.common.data.dao.ImagesDraftsDao
|
||||
import com.isolaatti.images.common.data.entity.ImageDraftEntity
|
||||
import com.isolaatti.images.common.data.remote.DeleteImagesDto
|
||||
import com.isolaatti.images.common.data.remote.ImagesApi
|
||||
import com.isolaatti.images.common.domain.entity.Image
|
||||
@ -20,7 +22,7 @@ import java.io.ByteArrayOutputStream
|
||||
import java.io.InputStream
|
||||
import javax.inject.Inject
|
||||
|
||||
class ImagesRepositoryImpl @Inject constructor(private val imagesApi: ImagesApi, private val contentResolver: ContentResolver) :
|
||||
class ImagesRepositoryImpl @Inject constructor(private val imagesApi: ImagesApi, private val imagesDraftsDao: ImagesDraftsDao, private val contentResolver: ContentResolver) :
|
||||
ImagesRepository {
|
||||
|
||||
companion object {
|
||||
@ -104,4 +106,12 @@ class ImagesRepositoryImpl @Inject constructor(private val imagesApi: ImagesApi,
|
||||
imageInputStream?.close()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDetachedDraftImages(): Flow<Resource<List<ImageDraftEntity>>> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun getDraftImagesOfPost(postId: Long): Flow<Resource<List<ImageDraftEntity>>> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
@ -9,7 +9,6 @@ import java.io.Serializable
|
||||
data class Image(
|
||||
val id: String,
|
||||
val userId: Int,
|
||||
val name: String,
|
||||
val username: String
|
||||
): Deletable(), Serializable {
|
||||
val imageUrl: String get() = UrlGen.imageUrl(id)
|
||||
@ -19,7 +18,7 @@ data class Image(
|
||||
val markdown: String get() = Generators.generateImage(imageUrl)
|
||||
|
||||
companion object {
|
||||
fun fromDto(imageDto: ImageDto) = Image(imageDto.id, imageDto.userId, imageDto.name, imageDto.username)
|
||||
fun fromDto(imageDto: ImageDto) = Image(imageDto.id, imageDto.userId, imageDto.username)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
@ -30,7 +29,6 @@ data class Image(
|
||||
|
||||
if (id != other.id) return false
|
||||
if (userId != other.userId) return false
|
||||
if (name != other.name) return false
|
||||
if (username != other.username) return false
|
||||
|
||||
return true
|
||||
@ -39,7 +37,6 @@ data class Image(
|
||||
override fun hashCode(): Int {
|
||||
var result = id.hashCode()
|
||||
result = 31 * result + userId
|
||||
result = 31 * result + name.hashCode()
|
||||
result = 31 * result + username.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.isolaatti.images.common.domain.repository
|
||||
|
||||
import android.net.Uri
|
||||
import com.isolaatti.images.common.data.entity.ImageDraftEntity
|
||||
import com.isolaatti.images.common.domain.entity.Image
|
||||
import com.isolaatti.utils.Resource
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@ -9,4 +10,6 @@ interface ImagesRepository {
|
||||
fun getImagesOfUser(userId: Int, lastId: String? = null): Flow<Resource<List<Image>>>
|
||||
fun deleteImages(images: List<Image>): Flow<Resource<Boolean>>
|
||||
fun uploadImage(name: String, imageUri: Uri, squadId: String?): Flow<Resource<Image>>
|
||||
fun getDetachedDraftImages(): Flow<Resource<List<ImageDraftEntity>>>
|
||||
fun getDraftImagesOfPost(postId: Long): Flow<Resource<List<ImageDraftEntity>>>
|
||||
}
|
||||
@ -5,9 +5,11 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import androidx.activity.result.contract.ActivityResultContract
|
||||
import androidx.core.content.IntentCompat
|
||||
import com.isolaatti.images.common.data.entity.ImageDraftEntity
|
||||
import com.isolaatti.images.common.domain.entity.Image
|
||||
|
||||
class ImageChooserContract : ActivityResultContract<ImageChooserContract.Requester, Image?>() {
|
||||
class ImageChooserContract : ActivityResultContract<ImageChooserContract.Requester, ImageDraftEntity?>() {
|
||||
|
||||
enum class Requester {
|
||||
UserPost, SquadPost
|
||||
@ -18,13 +20,13 @@ class ImageChooserContract : ActivityResultContract<ImageChooserContract.Request
|
||||
}
|
||||
}
|
||||
|
||||
override fun parseResult(resultCode: Int, intent: Intent?): Image? {
|
||||
override fun parseResult(resultCode: Int, intent: Intent?): ImageDraftEntity? {
|
||||
if(resultCode != Activity.RESULT_OK) { return null }
|
||||
|
||||
return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
||||
intent?.getSerializableExtra(ImageChooserActivity.OUTPUT_EXTRA_IMAGE) as Image?
|
||||
} else {
|
||||
intent?.getSerializableExtra(ImageChooserActivity.OUTPUT_EXTRA_IMAGE, Image::class.java)
|
||||
if(intent == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
return IntentCompat.getSerializableExtra(intent, ImageChooserActivity.OUTPUT_EXTRA_IMAGE, ImageDraftEntity::class.java)
|
||||
}
|
||||
}
|
||||
@ -38,7 +38,6 @@ class ImageChooserPreview : Fragment() {
|
||||
}
|
||||
|
||||
binding.image.load(viewModel.selectedImage?.imageUrl)
|
||||
binding.imageDescription.text = viewModel.selectedImage?.name
|
||||
|
||||
binding.chooseImageButton.setOnClickListener {
|
||||
showLoading(true)
|
||||
|
||||
@ -20,7 +20,6 @@ class PictureViewerMainFragment : Fragment() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
super.onPageSelected(position)
|
||||
binding.imageAuthor.text = images[position].username
|
||||
binding.imageDescription.text = images[position].name
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,7 +42,6 @@ class PictureViewerMainFragment : Fragment() {
|
||||
binding.viewpager.adapter = adapter
|
||||
binding.viewpager.setCurrentItem(position, false)
|
||||
binding.viewpager.registerOnPageChangeCallback(onPageChangeCallback)
|
||||
binding.imageDescription.text = images[position].name
|
||||
binding.imageAuthor.text = images[position].username
|
||||
}
|
||||
|
||||
|
||||
@ -123,10 +123,10 @@ class BottomSheetPostComments() : BottomSheetDialogFragment(), OnUserInteractedC
|
||||
}
|
||||
|
||||
private val imageChooserLauncher = registerForActivityResult(ImageChooserContract()) { image ->
|
||||
Log.d("BottomSheetPostComment", "${image?.markdown}")
|
||||
|
||||
|
||||
if(image != null) {
|
||||
viewBinding.newCommentTextField.editText?.setText("${viewBinding.newCommentTextField.editText?.text}\n\n${image.markdown}")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.isolaatti.posting.posts.presentation
|
||||
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
@ -21,6 +22,8 @@ import com.isolaatti.utils.Resource
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@ -48,6 +51,8 @@ class CreatePostViewModel @Inject constructor(
|
||||
val liveContent: MutableLiveData<String> = MutableLiveData()
|
||||
var content: String = ""
|
||||
set(value) {field = value; liveContent.value = value} // TODO remove this and use only liveContent
|
||||
private val _photos: MutableStateFlow<List<Uri>> = MutableStateFlow(emptyList())
|
||||
val photos: StateFlow<List<Uri>> get() = _photos
|
||||
|
||||
val audioAttachment: MutableLiveData<Playable?> = MutableLiveData()
|
||||
|
||||
@ -188,4 +193,13 @@ class CreatePostViewModel @Inject constructor(
|
||||
audioAttachment.value = null
|
||||
}
|
||||
|
||||
fun addPicture(uri: Uri) {
|
||||
_photos.value = listOf(uri) + _photos.value
|
||||
}
|
||||
|
||||
fun removePicture(index: Int) {
|
||||
_photos.value = _photos.value.toMutableList().apply {
|
||||
removeAt(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4,6 +4,7 @@ import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.activity.viewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.MediatorLiveData
|
||||
@ -41,6 +42,7 @@ class CreatePostActivity : IsolaattiBaseActivity() {
|
||||
var postId: Long = 0L
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
enableEdgeToEdge()
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
intent.extras?.let {
|
||||
@ -85,14 +87,6 @@ class CreatePostActivity : IsolaattiBaseActivity() {
|
||||
|
||||
binding.pager.adapter = CreatePostFragmentStateAdapter(this)
|
||||
|
||||
|
||||
TabLayoutMediator(binding.tabs, binding.pager) { tab, position ->
|
||||
when(position) {
|
||||
0 -> tab.setText(R.string.create_a_new_discussion)
|
||||
1 -> tab.setText(R.string.preview)
|
||||
}
|
||||
}.attach()
|
||||
|
||||
}
|
||||
|
||||
private fun setListeners() {
|
||||
|
||||
@ -6,14 +6,10 @@ import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
|
||||
class CreatePostFragmentStateAdapter(fragmentActivity: FragmentActivity) : FragmentStateAdapter(fragmentActivity) {
|
||||
override fun getItemCount(): Int {
|
||||
return 2
|
||||
return 1
|
||||
}
|
||||
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
return if(position == 0) {
|
||||
PostEditingFragment()
|
||||
} else {
|
||||
MarkdownPreviewFragment()
|
||||
}
|
||||
return PostEditingFragment()
|
||||
}
|
||||
}
|
||||
@ -1,12 +1,22 @@
|
||||
package com.isolaatti.posting.posts.ui
|
||||
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.activity.result.PickVisualMediaRequest
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
@ -14,6 +24,7 @@ import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import com.isolaatti.MyApplication
|
||||
import com.isolaatti.R
|
||||
import com.isolaatti.audio.audio_selector.ui.AudioSelectorContract
|
||||
import com.isolaatti.audio.common.domain.Audio
|
||||
@ -21,11 +32,15 @@ import com.isolaatti.audio.common.domain.Playable
|
||||
import com.isolaatti.audio.drafts.domain.AudioDraft
|
||||
import com.isolaatti.audio.player.AudioPlayerConnector
|
||||
import com.isolaatti.audio.recorder.ui.AudioRecorderContract
|
||||
import com.isolaatti.common.IsolaattiTheme
|
||||
import com.isolaatti.databinding.FragmentMarkdownEditingBinding
|
||||
import com.isolaatti.images.common.components.ImagesRow
|
||||
import com.isolaatti.images.image_chooser.ui.ImageChooserContract
|
||||
import com.isolaatti.posting.link_creator.presentation.LinkCreatorViewModel
|
||||
import com.isolaatti.posting.link_creator.ui.LinkCreatorFragment
|
||||
import com.isolaatti.posting.posts.presentation.CreatePostViewModel
|
||||
import java.io.File
|
||||
import java.util.Calendar
|
||||
|
||||
class PostEditingFragment : Fragment(){
|
||||
companion object {
|
||||
@ -47,11 +62,10 @@ class PostEditingFragment : Fragment(){
|
||||
}
|
||||
|
||||
private val imageChooserLauncher = registerForActivityResult(ImageChooserContract()) { image ->
|
||||
Log.d(LOG_TAG, "${image?.markdown}")
|
||||
|
||||
|
||||
if(image != null) {
|
||||
viewModel.content += "\n\n ${image.markdown}"
|
||||
binding.filledTextField.editText?.setText(viewModel.content)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -61,6 +75,25 @@ class PostEditingFragment : Fragment(){
|
||||
|
||||
}
|
||||
|
||||
private val choosePictureLauncher = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) {
|
||||
if(it != null) {
|
||||
viewModel.addPicture(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun makePhotoUri(): Uri {
|
||||
val cacheFile = File(requireContext().filesDir, "temp_picture_${Calendar.getInstance().timeInMillis}")
|
||||
return FileProvider.getUriForFile(requireContext(), "${MyApplication.myApp.packageName}.provider", cacheFile)
|
||||
}
|
||||
|
||||
private var cameraPhotoUri: Uri? = null
|
||||
|
||||
private val takePhotoLauncher = registerForActivityResult(ActivityResultContracts.TakePicture()) {
|
||||
if(it && cameraPhotoUri != null) {
|
||||
viewModel.addPicture(cameraPhotoUri!!)
|
||||
}
|
||||
|
||||
}
|
||||
private val audioListener = object: AudioPlayerConnector.Listener {
|
||||
override fun durationChanged(duration: Int, audio: Playable) {
|
||||
binding.audioItem.audioProgress.max = duration
|
||||
@ -112,6 +145,32 @@ class PostEditingFragment : Fragment(){
|
||||
|
||||
setupListeners()
|
||||
setupObservers()
|
||||
|
||||
binding.imagesRowCompose.apply {
|
||||
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
|
||||
setContent {
|
||||
val pictures by viewModel.photos.collectAsState()
|
||||
IsolaattiTheme {
|
||||
ImagesRow(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
images = pictures,
|
||||
deletable = true,
|
||||
addable = true,
|
||||
onClick = {},
|
||||
onDeleteClick = {
|
||||
viewModel.removePicture(it)
|
||||
},
|
||||
onTakePicture = {
|
||||
cameraPhotoUri = makePhotoUri()
|
||||
takePhotoLauncher.launch(cameraPhotoUri)
|
||||
},
|
||||
onUploadPicture = {
|
||||
choosePictureLauncher.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
@ -127,12 +186,6 @@ class PostEditingFragment : Fragment(){
|
||||
viewModel.validation.postValue(!text.isNullOrEmpty())
|
||||
viewModel.content = text.toString()
|
||||
}
|
||||
binding.addImageButton.setOnClickListener {
|
||||
insertImage()
|
||||
}
|
||||
binding.addLinkButton.setOnClickListener {
|
||||
insertLink()
|
||||
}
|
||||
|
||||
binding.addAudioButton.setOnClickListener {
|
||||
|
||||
|
||||
@ -128,7 +128,7 @@ class PostViewerActivity : IsolaattiBaseActivity() {
|
||||
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent?) {
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
super.onNewIntent(intent)
|
||||
|
||||
intent?.getLongExtra(POST_ID, 0)?.let {
|
||||
|
||||
@ -97,7 +97,7 @@ class ProfileMainFragment : Fragment() {
|
||||
private val chooseImageLauncher = registerForActivityResult(ImageChooserContract()) { image ->
|
||||
// here change profile picture
|
||||
if(image != null) {
|
||||
viewModel.setProfileImage(image)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -255,7 +255,6 @@ class ProfileMainFragment : Fragment() {
|
||||
Image(
|
||||
profile.profileImageId ?: "",
|
||||
profile.userId,
|
||||
getString(R.string.user_profile_picture, profile.name),
|
||||
profile.uniqueUsername)
|
||||
))
|
||||
}
|
||||
|
||||
5
app/src/main/res/drawable/baseline_add_a_photo_24.xml
Normal file
5
app/src/main/res/drawable/baseline_add_a_photo_24.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M3,4V1h2v3h3v2H5v3H3V6H0V4H3zM6,10V7h3V4h7l1.83,2H21c1.1,0 2,0.9 2,2v12c0,1.1 -0.9,2 -2,2H5c-1.1,0 -2,-0.9 -2,-2V10H6zM13,19c2.76,0 5,-2.24 5,-5s-2.24,-5 -5,-5s-5,2.24 -5,5S10.24,19 13,19zM9.8,14c0,1.77 1.43,3.2 3.2,3.2s3.2,-1.43 3.2,-3.2s-1.43,-3.2 -3.2,-3.2S9.8,12.23 9.8,14z"/>
|
||||
|
||||
</vector>
|
||||
@ -14,7 +14,8 @@
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:fitsSystemWindows="true">
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
@ -28,15 +29,6 @@
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/appBarLayout">
|
||||
|
||||
</com.google.android.material.tabs.TabLayout>
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/pager"
|
||||
@ -47,7 +39,7 @@
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tabs" />
|
||||
app:layout_constraintTop_toBottomOf="@+id/appBarLayout" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar_loading"
|
||||
|
||||
@ -23,23 +23,11 @@
|
||||
android:hint="@string/what_do_you_want_to_talk_about_you_can_record_an_audio_if_you_want"/>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/add_image_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
app:icon="@drawable/baseline_image_24" />
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/add_link_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
app:icon="@drawable/baseline_add_link_24" />
|
||||
</LinearLayout>
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/images_row_compose"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="160dp"/>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@ -58,7 +58,7 @@
|
||||
<string name="there_is_no_more_content_to_show">There is no more content to show</string>
|
||||
<string name="post">Post</string>
|
||||
<string name="add_image">Add image</string>
|
||||
<string name="what_do_you_want_to_talk_about_you_can_record_an_audio_if_you_want">What do you want to talk about? You can record an audio if you want.</string>
|
||||
<string name="what_do_you_want_to_talk_about_you_can_record_an_audio_if_you_want">What do you want to talk about?</string>
|
||||
<string name="posted_successfully">Posted!</string>
|
||||
<string name="drafts">Drafts</string>
|
||||
<string name="report_profile">Report profile</string>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user