Skip to content
This repository has been archived by the owner on Aug 20, 2024. It is now read-only.

Commit

Permalink
Initial support to reply on threads
Browse files Browse the repository at this point in the history
Signed-off-by: Aayush Gupta <[email protected]>
  • Loading branch information
theimpulson committed Aug 30, 2023
1 parent 53c901f commit 829d009
Show file tree
Hide file tree
Showing 11 changed files with 227 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package io.aayush.relabs.network
import io.aayush.relabs.network.data.alert.Alerts
import io.aayush.relabs.network.data.conversation.Conversations
import io.aayush.relabs.network.data.node.Nodes
import io.aayush.relabs.network.data.post.PostReply
import io.aayush.relabs.network.data.thread.ThreadInfo
import io.aayush.relabs.network.data.thread.Threads
import io.aayush.relabs.network.data.user.Me
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Path
import retrofit2.http.Query

Expand Down Expand Up @@ -64,4 +66,11 @@ interface XenforoInterface {
@Query("with_last_post") with_last_post: Boolean? = null,
@Query("order") order: String? = null
): Response<ThreadInfo>

@POST("posts")
suspend fun postReply(
@Query("thread_id") threadID: Int,
@Query("message") message: String,
@Query("attachment_key") attachmentKey: String? = null
): Response<PostReply>
}
20 changes: 20 additions & 0 deletions app/src/main/java/io/aayush/relabs/network/XenforoRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.util.Log
import io.aayush.relabs.network.data.alert.Alerts
import io.aayush.relabs.network.data.conversation.Conversations
import io.aayush.relabs.network.data.node.Nodes
import io.aayush.relabs.network.data.post.PostReply
import io.aayush.relabs.network.data.thread.ThreadInfo
import io.aayush.relabs.network.data.thread.Threads
import io.aayush.relabs.network.data.user.Me
Expand Down Expand Up @@ -170,4 +171,23 @@ class XenforoRepository @Inject constructor(
null
}
}

suspend fun postReply(
threadID: Int,
message: String,
attachmentKey: String? = null
): PostReply? {
return try {
val response = xenforoInterface.postReply(threadID, message, attachmentKey)
if (response.isSuccessful) {
response.body()
} else {
Log.i(TAG, "Status: ${response.code()}, ${response.errorBody()}")
null
}
} catch (exception: Exception) {
Log.e(TAG, "Failed to post reply!", exception)
null
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package io.aayush.relabs.network.data.post

data class PostReply(
val success: Boolean = false,
val post: Post = Post()
)
11 changes: 11 additions & 0 deletions app/src/main/java/io/aayush/relabs/ui/navigation/NavGraph.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import io.aayush.relabs.ui.screens.alerts.AlertsScreen
import io.aayush.relabs.ui.screens.home.HomeScreen
import io.aayush.relabs.ui.screens.login.LoginScreen
import io.aayush.relabs.ui.screens.news.NewsScreen
import io.aayush.relabs.ui.screens.reply.ReplyScreen
import io.aayush.relabs.ui.screens.settings.SettingsScreen
import io.aayush.relabs.ui.screens.thread.ThreadScreen

Expand Down Expand Up @@ -51,5 +52,15 @@ fun SetupNavGraph(
) {
ThreadScreen(navHostController, it.arguments!!.getInt(NavArg.THREAD_ID.name))
}
composable(
route = Screen.Reply.route,
arguments = listOf(
navArgument(NavArg.THREAD_ID.name) {
type = NavType.IntType
}
)
) {
ReplyScreen(navHostController, it.arguments!!.getInt(NavArg.THREAD_ID.name))
}
}
}
10 changes: 10 additions & 0 deletions app/src/main/java/io/aayush/relabs/ui/navigation/Screen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,14 @@ sealed class Screen(val route: String, @StringRes val title: Int, @DrawableRes v
return this.route.replace("{${NavArg.THREAD_ID.name}}", id.toString())
}
}

data object Reply : Screen(
route = "reply_screen/{${NavArg.THREAD_ID.name}}",
title = R.string.reply,
icon = R.drawable.ic_quick_reply
) {
fun withID(id: Int): String {
return this.route.replace("{${NavArg.THREAD_ID.name}}", id.toString())
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ fun LoginScreen(
navHostController: NavHostController,
viewModel: LoginScreenViewModel = hiltViewModel()
) {

val startActivityForResult = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult(),
onResult = {
Expand Down
112 changes: 112 additions & 0 deletions app/src/main/java/io/aayush/relabs/ui/screens/reply/ReplyScreen.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package io.aayush.relabs.ui.screens.reply

import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavHostController
import io.aayush.relabs.network.data.post.PostReply
import io.aayush.relabs.ui.navigation.Screen
import kotlinx.coroutines.flow.collectLatest

@Composable
@OptIn(ExperimentalMaterial3Api::class)
fun ReplyScreen(
navHostController: NavHostController,
threadID: Int,
viewModel: ReplyViewModel = hiltViewModel()
) {
var text by remember { mutableStateOf("") }
var posting by remember { mutableStateOf(false) }

val postReply: PostReply? by viewModel.postReply.collectAsStateWithLifecycle()

LaunchedEffect(key1 = postReply) {
snapshotFlow { postReply }.collectLatest {
if (it != null && it.success) {
navHostController.navigateUp()
} else {
posting = false
}
}
}

Scaffold(
topBar = {
TopAppBar(
title = { Text(text = stringResource(id = Screen.Reply.title)) },
navigationIcon = {
IconButton(onClick = { navHostController.navigateUp() }) {
Icon(
imageVector = Icons.Filled.ArrowBack,
contentDescription = ""
)
}
}
)
},
floatingActionButton = {
ExtendedFloatingActionButton(
text = { Text(text = stringResource(id = Screen.Reply.title)) },
icon = {
if (posting) {
CircularProgressIndicator()
} else {
Image(
painter = painterResource(id = Screen.Reply.icon),
contentDescription = ""
)
}
},
onClick = {
if (!posting && text.isNotBlank()) {
posting = true
viewModel.postReply(threadID, text)
}
}
)
}
) {
Column(
modifier = Modifier
.padding(it)
.fillMaxSize()
) {
OutlinedTextField(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(0.5f)
.padding(20.dp),
value = text,
onValueChange = { newText -> text = newText },
enabled = !posting
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.aayush.relabs.ui.screens.reply

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import io.aayush.relabs.network.XenforoRepository
import io.aayush.relabs.network.data.post.PostReply
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class ReplyViewModel @Inject constructor(
private val xenforoRepository: XenforoRepository
) : ViewModel() {

private val _postReply = MutableStateFlow<PostReply?>(PostReply())
val postReply = _postReply.asStateFlow()

fun postReply(threadID: Int, message: String) {
viewModelScope.launch(Dispatchers.IO) {
_postReply.value = xenforoRepository.postReply(threadID, message)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.aayush.relabs.ui.screens.thread

import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
Expand All @@ -18,6 +19,7 @@ import androidx.compose.material.icons.filled.KeyboardArrowLeft
import androidx.compose.material.icons.filled.KeyboardArrowRight
import androidx.compose.material3.Divider
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
Expand All @@ -30,13 +32,16 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavHostController
import io.aayush.relabs.network.data.thread.ThreadInfo
import io.aayush.relabs.ui.components.PostItem
import io.aayush.relabs.ui.navigation.Screen
import kotlinx.coroutines.launch

@Composable
Expand Down Expand Up @@ -72,6 +77,20 @@ fun ThreadScreen(
}
}
)
},
floatingActionButton = {
ExtendedFloatingActionButton(
text = { Text(text = stringResource(id = Screen.Reply.title)) },
icon = {
Image(
painter = painterResource(id = Screen.Reply.icon),
contentDescription = ""
)
},
onClick = {
navHostController.navigate(Screen.Reply.withID(threadID))
}
)
}
) {
Column(modifier = Modifier.padding(it)) {
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/res/drawable/ic_quick_reply.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M80,880L80,160Q80,127 103.5,103.5Q127,80 160,80L800,80Q833,80 856.5,103.5Q880,127 880,160L880,400L800,400L800,160Q800,160 800,160Q800,160 800,160L160,160Q160,160 160,160Q160,160 160,160L160,685L206,640L600,640L600,720L240,720L80,880ZM160,640L160,640L160,640L160,160Q160,160 160,160Q160,160 160,160L160,160Q160,160 160,160Q160,160 160,160L160,160L160,160L160,640ZM760,920L760,720L680,720L680,480L880,480L812,640L900,640L760,920Z"/>
</vector>
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,7 @@
<string name="op" translatable="false">\u2022OP\u2022</string>
<string name="reacted_to"><xliff:g id="number">%1$d</xliff:g> people reacted to this post</string>
<string name="you_and_reacted_to">You and <xliff:g id="number">%1$d</xliff:g> people reacted to this post</string>

<!-- ReplyScreen -->
<string name="reply">Reply</string>
</resources>

0 comments on commit 829d009

Please sign in to comment.