-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* create blog home screen UI * feat create post and list post on the blog home Screen * Feat multiple image selector ad event titles selector * done post details screen and like feature * modified listing post components on the log main screen * removed unused dependencies * Setting up test * Set Up Test * removed unused imports * reorganized ui components
- Loading branch information
1 parent
c8595cd
commit 7095671
Showing
52 changed files
with
1,983 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
98 changes: 98 additions & 0 deletions
98
.../java/com/yveskalume/eventcademy/core/data/firebase/repository/PostLikesRepositoryImpl.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package com.yveskalume.eventcademy.core.data.firebase.repository | ||
|
||
import android.util.Log | ||
import com.google.firebase.auth.FirebaseAuth | ||
import com.google.firebase.firestore.FirebaseFirestore | ||
import com.yveskalume.eventcademy.core.data.firebase.util.FirestoreCollections | ||
import com.yveskalume.eventcademy.core.domain.model.Post | ||
import com.yveskalume.eventcademy.core.domain.model.PostLike | ||
import com.yveskalume.eventcademy.core.domain.repository.PostLikesRepository | ||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.channels.awaitClose | ||
import kotlinx.coroutines.flow.callbackFlow | ||
import kotlinx.coroutines.flow.flowOn | ||
import kotlinx.coroutines.tasks.await | ||
import kotlinx.coroutines.withContext | ||
import java.util.Date | ||
import javax.inject.Inject | ||
|
||
class PostLikesRepositoryImpl @Inject constructor( | ||
private val firestore: FirebaseFirestore, | ||
private val firebaseAuth: FirebaseAuth | ||
|
||
):PostLikesRepository { | ||
|
||
override fun getAllLikesByPostUid(postUid: String) = callbackFlow<List<PostLike>> { | ||
val listener = firestore.collection(FirestoreCollections.LIKES) | ||
.whereEqualTo(PostLike::postUid.name, postUid) | ||
.addSnapshotListener{value, error-> | ||
if (error != null || value == null){ | ||
close(error) | ||
return@addSnapshotListener | ||
} | ||
value.toObjects(PostLike::class.java).also { | ||
trySend(it) | ||
} | ||
} | ||
awaitClose{ listener.remove() } | ||
}.flowOn(Dispatchers.IO) | ||
|
||
override fun getAllUserPostLikes() = callbackFlow<List<PostLike>> { | ||
val currentUser = firebaseAuth.currentUser | ||
val listener = firestore.collection(FirestoreCollections.LIKES) | ||
.whereEqualTo(PostLike::userUid.name, currentUser?.uid) | ||
.addSnapshotListener{value, error-> | ||
if (error != null || value == null){ | ||
close(error) | ||
return@addSnapshotListener | ||
} | ||
value.toObjects(PostLike::class.java).also {data-> | ||
trySend(data.sortedBy { it.createdAt }) | ||
} | ||
} | ||
awaitClose{listener.remove()} | ||
}.flowOn(Dispatchers.IO) | ||
|
||
override suspend fun checkIfUserHasLiked(postUid: String) = callbackFlow { | ||
val currentUser = firebaseAuth.currentUser | ||
val listener = firestore | ||
.document("${FirestoreCollections.LIKES}/${currentUser?.uid}-$postUid") | ||
.addSnapshotListener{value, error -> | ||
if (error != null || value == null){ | ||
Log.e("checkIfUserHasLiked","error",error) | ||
trySend(false) | ||
return@addSnapshotListener | ||
} | ||
trySend(value.exists()) | ||
} | ||
awaitClose{listener.remove()} | ||
}.flowOn(Dispatchers.IO) | ||
|
||
override suspend fun createLike(post: Post) { | ||
withContext(Dispatchers.IO){ | ||
val currentUser = firebaseAuth.currentUser ?: return@withContext | ||
val postLike = PostLike( | ||
uid = "${currentUser.uid}-${post.uid}", | ||
postUid = post.uid, | ||
postImageUrl = post.imageUrls, | ||
userUid = currentUser.uid, | ||
userName = currentUser.displayName ?: "", | ||
email = currentUser.email ?: "", | ||
userPhotoUrl = currentUser.photoUrl.toString(), | ||
createdAt = Date().toString() | ||
) | ||
firestore.document("${FirestoreCollections.LIKES}/${postLike.uid}") | ||
.set(postLike) | ||
.await() | ||
} | ||
} | ||
|
||
override suspend fun deleteLike(postUid: String) { | ||
withContext(Dispatchers.IO){ | ||
val current = firebaseAuth.currentUser ?: return@withContext | ||
firestore.document("${FirestoreCollections.LIKES}/${current.uid}-$postUid") | ||
.delete() | ||
.await() | ||
} | ||
} | ||
} |
113 changes: 113 additions & 0 deletions
113
.../main/java/com/yveskalume/eventcademy/core/data/firebase/repository/PostRepositoryImpl.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package com.yveskalume.eventcademy.core.data.firebase.repository | ||
|
||
import android.net.Uri | ||
import com.google.firebase.auth.FirebaseAuth | ||
import com.google.firebase.firestore.FirebaseFirestore | ||
import com.google.firebase.storage.FirebaseStorage | ||
import com.yveskalume.eventcademy.core.data.firebase.util.FirebaseStorageFolders | ||
import com.yveskalume.eventcademy.core.data.firebase.util.FirestoreCollections | ||
import com.yveskalume.eventcademy.core.domain.model.Event | ||
import com.yveskalume.eventcademy.core.domain.model.Post | ||
import com.yveskalume.eventcademy.core.domain.repository.PostRepository | ||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.channels.awaitClose | ||
import kotlinx.coroutines.flow.Flow | ||
import kotlinx.coroutines.flow.callbackFlow | ||
import kotlinx.coroutines.flow.flowOn | ||
import kotlinx.coroutines.tasks.await | ||
import kotlinx.coroutines.withContext | ||
import java.util.Date | ||
import javax.inject.Inject | ||
|
||
class PostRepositoryImpl @Inject constructor( | ||
private val firestore: FirebaseFirestore, | ||
private val firebaseAuth: FirebaseAuth, | ||
private val firebaseStorage: FirebaseStorage | ||
): PostRepository { | ||
|
||
/** | ||
* Create a post | ||
* @param post the post to create | ||
* @throws IllegalStateException if the user is not connected | ||
*/ | ||
override suspend fun createPost(post: Post) { | ||
withContext(Dispatchers.IO){ | ||
val user = firebaseAuth.currentUser | ||
if (user == null){ | ||
throw IllegalStateException("Vous devez être connecté pour créer un Post") | ||
} else { | ||
val imageUrl = uploadPostImage(post) | ||
|
||
val postToCreate = post.copy( | ||
userUid = user.uid, | ||
createdAt = Date(), | ||
updatedAt = Date(), | ||
imageUrls = imageUrl | ||
) | ||
|
||
val task = firestore.document("${FirestoreCollections.POSTS}/${postToCreate.uid}") | ||
.set(postToCreate) | ||
task.await() | ||
} | ||
} | ||
} | ||
|
||
|
||
/** | ||
* Get all the post created by the current user | ||
* @return a list of posts | ||
*/ | ||
|
||
private suspend fun uploadPostImage(post: Post): List<String>{ | ||
return withContext(Dispatchers.IO){ | ||
val urls = mutableListOf<String>() | ||
for ((index, imageUri) in post.imageUrls.withIndex()){ | ||
val imageUrl = Uri.parse(imageUri) | ||
val imageRef = firebaseStorage | ||
.reference.child("${FirebaseStorageFolders.posts}/${post.uid}/image_$index") | ||
|
||
val uploadTask = imageRef.putFile(imageUrl) | ||
uploadTask.await() | ||
urls.add(imageRef.downloadUrl.await().toString()) | ||
} | ||
|
||
return@withContext urls | ||
} | ||
} | ||
|
||
override fun getAllPosts()= callbackFlow<List<Post>> { | ||
val listener = firestore.collection(FirestoreCollections.POSTS) | ||
.addSnapshotListener { value, error -> | ||
if (error != null || value == null) { | ||
close(error) | ||
return@addSnapshotListener | ||
} | ||
value.toObjects(Post::class.java).also { data -> | ||
trySend(data.sortedBy { it.createdAt }) | ||
} | ||
} | ||
awaitClose { listener.remove() } | ||
}.flowOn(Dispatchers.IO) | ||
|
||
|
||
/** | ||
* Delete a post | ||
* @param postUid the uid of the post to delete | ||
*/ | ||
override suspend fun deletePost(postUid: String) { | ||
withContext(Dispatchers.IO){ | ||
firestore.document("${FirestoreCollections.POSTS}/$postUid").delete().await() | ||
firebaseStorage.reference.child("${FirebaseStorageFolders.posts}/$postUid") | ||
.delete() | ||
.await() | ||
} | ||
} | ||
|
||
override suspend fun getPostByUid(postUid: String): Post? { | ||
return withContext(Dispatchers.IO){ | ||
val task = firestore.document("${FirestoreCollections.POSTS}/$postUid").get() | ||
val post = task.await().toObject(Post::class.java) | ||
return@withContext post | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
76 changes: 76 additions & 0 deletions
76
...em/src/main/java/com/yveskalume/eventcademy/core/designsystem/components/EventSelector.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package com.yveskalume.eventcademy.core.designsystem.components | ||
|
||
import androidx.compose.foundation.clickable | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.fillMaxWidth | ||
import androidx.compose.foundation.layout.padding | ||
import androidx.compose.material.icons.Icons | ||
import androidx.compose.material.icons.outlined.KeyboardArrowDown | ||
import androidx.compose.material3.Divider | ||
import androidx.compose.material3.DropdownMenu | ||
import androidx.compose.material3.DropdownMenuItem | ||
import androidx.compose.material3.Icon | ||
import androidx.compose.material3.IconButton | ||
import androidx.compose.material3.OutlinedTextField | ||
import androidx.compose.material3.Text | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.ui.Alignment | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.graphics.Color | ||
import androidx.compose.ui.text.TextStyle | ||
import androidx.compose.ui.unit.dp | ||
import com.yveskalume.eventcademy.core.domain.model.Event | ||
|
||
@Composable | ||
fun EventSelector( | ||
modifier: Modifier = Modifier, | ||
value: String, | ||
eventList: List<Event>, | ||
showSelector: Boolean, | ||
onValueChange: (String) -> Unit, | ||
onIconClicked: () -> Unit, | ||
onEventClicked: () -> Unit | ||
){ | ||
Column( | ||
modifier = modifier | ||
.fillMaxWidth() | ||
.padding(vertical = 4.dp), | ||
horizontalAlignment = Alignment.CenterHorizontally | ||
) { | ||
|
||
OutlinedTextField( | ||
modifier = modifier | ||
.fillMaxWidth().clickable( | ||
onClick = { | ||
onIconClicked() | ||
} | ||
), | ||
readOnly = true, | ||
placeholder = { | ||
Text(text = "Selectionnez un événement") | ||
}, | ||
value = value, | ||
onValueChange = { onValueChange }, | ||
trailingIcon = { | ||
IconButton(onClick = onIconClicked) { | ||
Icon(imageVector = Icons.Outlined.KeyboardArrowDown, contentDescription = null) | ||
} | ||
} | ||
) | ||
|
||
DropdownMenu(expanded = showSelector, onDismissRequest = onIconClicked) { | ||
eventList.forEach { | ||
DropdownMenuItem( | ||
text = { | ||
Text(text = it.name) | ||
}, | ||
onClick = { | ||
onValueChange(it.name) | ||
onEventClicked() | ||
} | ||
) | ||
Divider() | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.