Skip to content

Commit 569dfce

Browse files
article pages done
Signed-off-by: Arnav Gupta <[email protected]>
1 parent 11cc6d5 commit 569dfce

File tree

8 files changed

+198
-13
lines changed

8 files changed

+198
-13
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package io.realworld.android.ui.article
2+
3+
import android.os.Bundle
4+
import android.view.LayoutInflater
5+
import android.view.View
6+
import android.view.ViewGroup
7+
import androidx.fragment.app.Fragment
8+
import androidx.lifecycle.ViewModelProvider
9+
import io.realworld.android.R
10+
import io.realworld.android.databinding.FragmentArticleBinding
11+
12+
class ArticleFragment : Fragment() {
13+
14+
private var _binding: FragmentArticleBinding? = null
15+
lateinit var articleViewModel: ArticleViewModel
16+
private var articleId: String? = null
17+
18+
override fun onCreateView(
19+
inflater: LayoutInflater,
20+
container: ViewGroup?,
21+
savedInstanceState: Bundle?
22+
): View? {
23+
articleViewModel = ViewModelProvider(this).get(ArticleViewModel::class.java)
24+
_binding = FragmentArticleBinding.inflate(inflater, container, false)
25+
26+
arguments?.let {
27+
articleId = it.getString(resources.getString(R.string.arg_article_id))
28+
}
29+
30+
articleId?.let { articleViewModel.fetchArticle(it) }
31+
32+
return _binding?.root
33+
}
34+
35+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
36+
super.onViewCreated(view, savedInstanceState)
37+
38+
articleViewModel.article.observe({ lifecycle }) {
39+
_binding?.apply {
40+
titleTextView.text = it.title
41+
bodyTextView.text = it.body
42+
authorTextView.text = it.author.username
43+
dateTextView.text = it.createdAt // TODO: format
44+
}
45+
}
46+
47+
48+
}
49+
50+
override fun onDestroyView() {
51+
super.onDestroyView()
52+
_binding = null
53+
}
54+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package io.realworld.android.ui.article
2+
3+
import androidx.lifecycle.LiveData
4+
import androidx.lifecycle.MutableLiveData
5+
import androidx.lifecycle.ViewModel
6+
import androidx.lifecycle.viewModelScope
7+
import io.realworld.api.ConduitClient
8+
import io.realworld.api.models.entities.Article
9+
import kotlinx.coroutines.launch
10+
11+
class ArticleViewModel : ViewModel() {
12+
val api = ConduitClient.publicApi
13+
14+
private val _article = MutableLiveData<Article>()
15+
val article: LiveData<Article> = _article
16+
17+
fun fetchArticle(slug: String) = viewModelScope.launch {
18+
val response = api.getArticleBySlug(slug)
19+
20+
response.body()?.article.let { _article.postValue(it) }
21+
22+
}
23+
}

app/src/main/java/io/realworld/android/ui/feed/ArticleFeedAdapter.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import io.realworld.android.R
1212
import io.realworld.android.databinding.ListItemArticleBinding
1313
import io.realworld.api.models.entities.Article
1414

15-
class ArticleFeedAdapter : ListAdapter<Article, ArticleFeedAdapter.ArticleViewHolder>(
15+
class ArticleFeedAdapter(val onArticleClicked: (slug: String) -> Unit) : ListAdapter<Article, ArticleFeedAdapter.ArticleViewHolder>(
1616
object : DiffUtil.ItemCallback<Article>() {
1717
override fun areItemsTheSame(oldItem: Article, newItem: Article): Boolean {
1818
return oldItem == newItem
@@ -23,8 +23,6 @@ class ArticleFeedAdapter : ListAdapter<Article, ArticleFeedAdapter.ArticleViewHo
2323
}
2424
}
2525
) {
26-
27-
2826
inner class ArticleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
2927

3028
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArticleViewHolder {
@@ -44,8 +42,10 @@ class ArticleFeedAdapter : ListAdapter<Article, ArticleFeedAdapter.ArticleViewHo
4442
authorTextView.text = article.author.username
4543
titleTextView.text = article.title
4644
bodySnippetTextView.text = article.body
47-
dateTextView.text = "December 15, 2020"
48-
avatarImageView.background = ColorDrawable(Color.GRAY)
45+
dateTextView.text = "December 15, 2020" //TODO: format actual date
46+
avatarImageView.background = ColorDrawable(Color.GRAY) //TODO: show real image
47+
48+
root.setOnClickListener { onArticleClicked(article.slug) }
4949

5050
}
5151

app/src/main/java/io/realworld/android/ui/feed/GlobalFeedFragment.kt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ import android.os.Bundle
44
import android.view.LayoutInflater
55
import android.view.View
66
import android.view.ViewGroup
7+
import androidx.core.os.bundleOf
78
import androidx.fragment.app.Fragment
89
import androidx.lifecycle.ViewModelProvider
10+
import androidx.navigation.fragment.findNavController
911
import androidx.recyclerview.widget.LinearLayoutManager
12+
import io.realworld.android.R
1013
import io.realworld.android.databinding.FragmentFeedBinding
1114

1215
class GlobalFeedFragment : Fragment() {
@@ -20,7 +23,7 @@ class GlobalFeedFragment : Fragment() {
2023
savedInstanceState: Bundle?
2124
): View? {
2225
viewModel = ViewModelProvider(this).get(FeedViewModel::class.java)
23-
feedAdapter = ArticleFeedAdapter()
26+
feedAdapter = ArticleFeedAdapter { openArticle(it) }
2427

2528
_binding = FragmentFeedBinding.inflate(inflater, container, false)
2629
_binding?.feedRecyclerView?.layoutManager = LinearLayoutManager(context)
@@ -34,8 +37,15 @@ class GlobalFeedFragment : Fragment() {
3437
viewModel.feed.observe({ lifecycle }) {
3538
feedAdapter.submitList(it)
3639
}
40+
}
3741

38-
42+
fun openArticle(articleId: String) {
43+
findNavController().navigate(
44+
R.id.action_globalFeed_openArticle,
45+
bundleOf(
46+
resources.getString(R.string.arg_article_id) to articleId
47+
)
48+
)
3949
}
4050

4151
override fun onDestroyView() {

app/src/main/java/io/realworld/android/ui/feed/MyFeedFragment.kt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ import android.os.Bundle
44
import android.view.LayoutInflater
55
import android.view.View
66
import android.view.ViewGroup
7+
import androidx.core.os.bundleOf
78
import androidx.fragment.app.Fragment
89
import androidx.lifecycle.ViewModelProvider
10+
import androidx.navigation.fragment.findNavController
911
import androidx.recyclerview.widget.LinearLayoutManager
12+
import io.realworld.android.R
1013
import io.realworld.android.databinding.FragmentFeedBinding
1114

1215
class MyFeedFragment : Fragment() {
@@ -21,7 +24,7 @@ class MyFeedFragment : Fragment() {
2124
savedInstanceState: Bundle?
2225
): View? {
2326
viewModel = ViewModelProvider(this).get(FeedViewModel::class.java)
24-
feedAdapter = ArticleFeedAdapter()
27+
feedAdapter = ArticleFeedAdapter { openArticle(it) }
2528

2629
_binding = FragmentFeedBinding.inflate(inflater, container, false)
2730
_binding?.feedRecyclerView?.layoutManager = LinearLayoutManager(context)
@@ -35,10 +38,16 @@ class MyFeedFragment : Fragment() {
3538
viewModel.feed.observe({ lifecycle }) {
3639
feedAdapter.submitList(it)
3740
}
38-
39-
4041
}
4142

43+
fun openArticle(articleId: String) {
44+
findNavController().navigate(
45+
R.id.action_globalFeed_openArticle,
46+
bundleOf(
47+
resources.getString(R.string.arg_article_id) to articleId
48+
)
49+
)
50+
}
4251
override fun onDestroyView() {
4352
super.onDestroyView()
4453
_binding = null
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools"
4+
android:layout_width="match_parent"
5+
android:layout_height="match_parent"
6+
android:orientation="vertical"
7+
android:padding="10dp">
8+
9+
<TextView
10+
android:id="@+id/titleTextView"
11+
android:layout_width="match_parent"
12+
android:layout_height="wrap_content"
13+
android:maxLines="2"
14+
android:padding="4dp"
15+
android:textAppearance="@style/TextAppearance.AppCompat.Headline"
16+
tools:text="Title of the Article" />
17+
18+
<LinearLayout
19+
android:layout_width="match_parent"
20+
android:layout_height="wrap_content"
21+
android:gravity="center_vertical"
22+
android:padding="4dp">
23+
24+
<ImageView
25+
android:id="@+id/avatarImageView"
26+
android:layout_width="32dp"
27+
android:layout_height="32dp"
28+
android:background="@color/conduit_grey" />
29+
30+
<LinearLayout
31+
android:layout_width="wrap_content"
32+
android:layout_height="wrap_content"
33+
android:layout_marginLeft="10dp"
34+
android:orientation="vertical">
35+
36+
<TextView
37+
android:id="@+id/authorTextView"
38+
android:layout_width="wrap_content"
39+
android:layout_height="wrap_content"
40+
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
41+
tools:text="username" />
42+
43+
<TextView
44+
android:id="@+id/dateTextView"
45+
android:layout_width="wrap_content"
46+
android:layout_height="wrap_content"
47+
android:textAppearance="@style/TextAppearance.AppCompat.Caption"
48+
tools:text="December 15, 2020" />
49+
</LinearLayout>
50+
</LinearLayout>
51+
52+
<TextView
53+
android:id="@+id/bodyTextView"
54+
android:layout_width="match_parent"
55+
android:layout_height="wrap_content"
56+
android:maxLines="2"
57+
android:padding="4dp"
58+
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
59+
tools:text="ad deser Sunt error ad deser Sunt error ad deser Sunt error ad deser Sunt error ad deser Sunt error ad deser Sunt error ad deser Sunt error ad deser Sunt error ad deser Sunt error ad deser Sunt error ad deser Sunt error ad deser Sunt error ad deser Sunt error ad deser Sunt error ad deser Sunt error ad deser Sunt error" />
60+
61+
62+
</LinearLayout>

app/src/main/res/navigation/navigation_main.xml

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,46 @@
99
android:id="@+id/nav_feed"
1010
android:name="io.realworld.android.ui.feed.GlobalFeedFragment"
1111
android:label="@string/menu_feed"
12-
tools:layout="@layout/fragment_feed" />
12+
tools:layout="@layout/fragment_feed">
13+
<action
14+
android:id="@+id/action_globalFeed_openArticle"
15+
app:destination="@id/nav_article"
16+
app:popUpTo="@id/nav_feed">
17+
<argument
18+
android:name="@string/arg_article_id"
19+
app:argType="string" />
20+
</action>
21+
</fragment>
1322

1423
<fragment
1524
android:id="@+id/nav_my_feed"
1625
android:name="io.realworld.android.ui.feed.MyFeedFragment"
1726
android:label="@string/menu_my_feed"
18-
tools:layout="@layout/fragment_feed" />
27+
tools:layout="@layout/fragment_feed">
28+
<action
29+
android:id="@+id/action_myFeed_openArticle"
30+
app:destination="@id/nav_article"
31+
app:popUpTo="@id/nav_my_feed">
32+
<argument
33+
android:name="@string/arg_article_id"
34+
app:argType="string" />
35+
</action>
36+
</fragment>
1937

2038
<fragment
2139
android:id="@+id/nav_auth"
2240
android:name="io.realworld.android.ui.auth.AuthFragment"
2341
android:label="@string/menu_auth"
24-
tools:layout="@layout/fragment_auth"/>
42+
tools:layout="@layout/fragment_auth" />
2543

2644
<fragment
2745
android:id="@+id/nav_settings"
2846
android:name="io.realworld.android.ui.settings.SettingsFragment"
2947
android:label="@string/menu_settings"
3048
tools:layout="@layout/fragment_feed" />
49+
50+
<fragment
51+
android:id="@+id/nav_article"
52+
android:name="io.realworld.android.ui.article.ArticleFragment"
53+
tools:layout="@layout/fragment_article" />
3154
</navigation>

app/src/main/res/values/strings.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,8 @@
1111
<string name="menu_my_feed">My Feed</string>
1212
<string name="menu_auth">Login / Signup</string>
1313
<string name="menu_settings">Settings</string>
14+
15+
16+
<string name="arg_article_id">ARTICLE_ID</string>
17+
1418
</resources>

0 commit comments

Comments
 (0)