Add loading indications, refactor fragments into common parent class

This commit is contained in:
Matthieu 2020-03-21 18:12:00 +01:00
parent 55cb729a2d
commit 0a3cd85d83
19 changed files with 404 additions and 382 deletions

View File

@ -6,6 +6,7 @@ import android.content.Intent
import android.content.SharedPreferences
import android.net.Uri
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.browser.customtabs.CustomTabsIntent
import com.h.pixeldroid.api.PixelfedAPI
@ -42,20 +43,26 @@ class LoginActivity : AppCompatActivity() {
val url = intent.data
//Check if the activity was started after the authentication
if (url == null || !url.toString().startsWith("$OAUTH_SCHEME://$PACKAGE_ID")) return
loadingAnimation(true)
val code = url.getQueryParameter("code")
authenticate(code)
}
override fun onStop() {
super.onStop()
loadingAnimation(false)
}
override fun onBackPressed() {
}
private fun onClickConnect() {
connect_instance_button.isEnabled = false
val normalizedDomain = normalizeDomain(editText.text.toString())
try{
@ -64,6 +71,8 @@ class LoginActivity : AppCompatActivity() {
return failedRegistration(getString(R.string.invalid_domain))
}
loadingAnimation(true)
preferences.edit()
.putString("domain", "https://$normalizedDomain")
.apply()
@ -125,7 +134,6 @@ class LoginActivity : AppCompatActivity() {
return failedRegistration(getString(R.string.browser_launch_failed))
}
}
connect_instance_button.isEnabled = true
}
private fun authenticate(code: String?) {
@ -169,8 +177,19 @@ class LoginActivity : AppCompatActivity() {
private fun failedRegistration(message: String =
getString(R.string.registration_failed)){
connect_instance_button.isEnabled = true
loadingAnimation(false)
editText.error = message
}
private fun loadingAnimation(on: Boolean){
if(on) {
domainTextInputLayout.visibility = View.GONE
progressLayout.visibility = View.VISIBLE
}
else {
domainTextInputLayout.visibility = View.VISIBLE
progressLayout.visibility = View.GONE
}
}
}

View File

@ -17,9 +17,9 @@ import com.google.android.material.navigation.NavigationView
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import com.h.pixeldroid.fragments.CameraFragment
import com.h.pixeldroid.fragments.HomeFragment
import com.h.pixeldroid.fragments.feeds.HomeFragment
import com.h.pixeldroid.fragments.MyProfileFragment
import com.h.pixeldroid.fragments.NotificationsFragment
import com.h.pixeldroid.fragments.feeds.NotificationsFragment
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
@ -46,10 +46,11 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
val navigationView: NavigationView = findViewById(R.id.nav_view)
navigationView.setNavigationItemSelectedListener(this)
val tabs = arrayOf(HomeFragment(),
val tabs = arrayOf(
HomeFragment(),
Fragment(),
CameraFragment(),
NotificationsFragment(),
NotificationsFragment(),
MyProfileFragment())
setupTabs(tabs)

View File

@ -3,8 +3,8 @@ package com.h.pixeldroid
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.h.pixeldroid.fragments.PostFragment
import com.h.pixeldroid.models.Post
import com.h.pixeldroid.models.Post.Companion.POST_TAG
import com.h.pixeldroid.objects.Status.Companion.POST_TAG
import com.h.pixeldroid.objects.Status
class PostActivity : AppCompatActivity() {
@ -14,11 +14,11 @@ class PostActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_post)
val post = intent.getSerializableExtra(POST_TAG) as Post
val status = intent.getSerializableExtra(POST_TAG) as Status
postFragment = PostFragment()
val arguments = Bundle()
arguments.putSerializable(POST_TAG, post)
arguments.putSerializable(POST_TAG, status)
postFragment.arguments = arguments
supportFragmentManager.beginTransaction()

View File

@ -1,78 +0,0 @@
package com.h.pixeldroid.fragments
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.h.pixeldroid.BuildConfig
import com.h.pixeldroid.R
import com.h.pixeldroid.api.PixelfedAPI
import com.h.pixeldroid.models.Post
import com.h.pixeldroid.objects.Status
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class HomeFragment : Fragment() {
private lateinit var preferences: SharedPreferences
private lateinit var feed : RecyclerView
private lateinit var adapter : FeedRecyclerViewAdapter
private lateinit var posts : List<Post>
fun setContent(newPosts : ArrayList<Post>) {
posts = newPosts
adapter.addPosts(posts)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_home, container, false)
preferences = this.activity!!.getSharedPreferences(
"${BuildConfig.APPLICATION_ID}.pref", Context.MODE_PRIVATE
)
feed = view.findViewById(R.id.feedList)
feed.layoutManager = LinearLayoutManager(context)
adapter = FeedRecyclerViewAdapter(context!!)
feed.adapter = adapter
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val pixelfedAPI = PixelfedAPI.create("${preferences.getString("domain", "")}")
val accessToken = preferences.getString("accessToken", "")
var statuses: ArrayList<Status>? = null
val newPosts = ArrayList<Post>()
pixelfedAPI.timelineHome("Bearer $accessToken")
.enqueue(object : Callback<List<Status>> {
override fun onResponse(call: Call<List<Status>>, response: Response<List<Status>>) {
if (response.code() == 200) {
statuses = response.body() as ArrayList<Status>?
if(!statuses.isNullOrEmpty()) {
for (status in statuses!!) {
newPosts.add(Post(status))
}
setContent(newPosts)
}
}
}
override fun onFailure(call: Call<List<Status>>, t: Throwable) {
Log.e("HomeFragment", t.toString())
}
})
}
}

View File

@ -1,99 +0,0 @@
package com.h.pixeldroid.fragments
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener
import com.h.pixeldroid.BuildConfig
import com.h.pixeldroid.R
import com.h.pixeldroid.api.PixelfedAPI
import com.h.pixeldroid.objects.Notification
import kotlinx.android.synthetic.main.fragment_notifications_list.*
import kotlinx.android.synthetic.main.fragment_notifications_list.view.*
import kotlinx.android.synthetic.main.fragment_notifications_list.view.swipeRefreshLayout
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
/**
* A fragment representing a list of Items.
*/
class NotificationsFragment : Fragment() {
private lateinit var preferences: SharedPreferences
private lateinit var list : RecyclerView
private lateinit var adapter : NotificationsRecyclerViewAdapter
private lateinit var swipeRefreshLayout: SwipeRefreshLayout
var notifications : List<Notification> = ArrayList()
private lateinit var pixelfedAPI: PixelfedAPI
private var accessToken: String? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_notifications_list, container, false)
preferences = activity!!.getSharedPreferences(
"${BuildConfig.APPLICATION_ID}.pref", Context.MODE_PRIVATE
)
pixelfedAPI = PixelfedAPI.create("${preferences.getString("domain", "")}")
accessToken = preferences.getString("accessToken", "")
swipeRefreshLayout = view.findViewById(R.id.swipeRefreshLayout)
list = swipeRefreshLayout.list
// Set the adapter
list.layoutManager = LinearLayoutManager(context)
adapter = NotificationsRecyclerViewAdapter()
list.adapter = adapter
swipeRefreshLayout.setOnRefreshListener {
doRequest()
}
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
doRequest()
}
fun setContent(notifications : ArrayList<Notification>) {
this.notifications = notifications
adapter.initializeWith(notifications)
}
private fun doRequest(){
val call = pixelfedAPI.notifications("Bearer $accessToken", min_id="1")
call.enqueue(object : Callback<List<Notification>> {
override fun onResponse(call: Call<List<Notification>>, response: Response<List<Notification>>) {
if (response.code() == 200) {
val notifications = response.body()!! as ArrayList<Notification>
setContent(notifications)
} else{
Toast.makeText(context,"Something went wrong while refreshing", Toast.LENGTH_SHORT).show()
}
swipeRefreshLayout.isRefreshing = false
}
override fun onFailure(call: Call<List<Notification>>, t: Throwable) {
Toast.makeText(context,"Could not get notifications", Toast.LENGTH_SHORT).show()
Log.e("Notifications", t.toString())
}
})
}
}

View File

@ -6,8 +6,8 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.h.pixeldroid.R
import com.h.pixeldroid.models.Post
import com.h.pixeldroid.models.Post.Companion.POST_TAG
import com.h.pixeldroid.objects.Status.Companion.POST_TAG
import com.h.pixeldroid.objects.Status
class PostFragment : Fragment() {
@ -16,9 +16,9 @@ class PostFragment : Fragment() {
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val post = arguments?.getSerializable(POST_TAG) as Post?
val status = arguments?.getSerializable(POST_TAG) as Status?
val root = inflater.inflate(R.layout.post_fragment, container, false)
post?.setupPost(this, root)
status?.setupPost(this, root)
return root
}

View File

@ -0,0 +1,98 @@
package com.h.pixeldroid.fragments.feeds
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.h.pixeldroid.BuildConfig
import com.h.pixeldroid.R
import com.h.pixeldroid.api.PixelfedAPI
import kotlinx.android.synthetic.main.fragment_feed.*
import kotlinx.android.synthetic.main.fragment_feed.view.*
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
open class FeedFragment<T, VH: RecyclerView.ViewHolder?>: Fragment() {
var content : List<T> = ArrayList()
protected var accessToken: String? = null
protected lateinit var pixelfedAPI: PixelfedAPI
protected lateinit var preferences: SharedPreferences
protected lateinit var list : RecyclerView
protected lateinit var adapter : FeedsRecyclerViewAdapter<T, VH>
private lateinit var swipeRefreshLayout: SwipeRefreshLayout
protected fun doRequest(call: Call<List<T>>){
call.enqueue(object : Callback<List<T>> {
override fun onResponse(call: Call<List<T>>, response: Response<List<T>>) {
if (response.code() == 200) {
val notifications = response.body()!! as ArrayList<T>
setContent(notifications)
} else{
Toast.makeText(context,"Something went wrong while loading", Toast.LENGTH_SHORT).show()
}
swipeRefreshLayout.isRefreshing = false
progressBar.visibility = View.GONE
}
override fun onFailure(call: Call<List<T>>, t: Throwable) {
Toast.makeText(context,"Could not get feed", Toast.LENGTH_SHORT).show()
Log.e("FeedFragment", t.toString())
}
})
}
protected fun setContent(content : ArrayList<T>) {
this.content = content
adapter.initializeWith(content)
}
protected fun onCreateView(inflater: LayoutInflater, container: ViewGroup?): View? {
val view = inflater.inflate(R.layout.fragment_feed, container, false)
swipeRefreshLayout = view.findViewById(R.id.swipeRefreshLayout)
list = swipeRefreshLayout.list
// Set the adapter
list.layoutManager = LinearLayoutManager(context)
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
preferences = activity!!.getSharedPreferences(
"${BuildConfig.APPLICATION_ID}.pref", Context.MODE_PRIVATE
)
pixelfedAPI = PixelfedAPI.create("${preferences.getString("domain", "")}")
accessToken = preferences.getString("accessToken", "")
}
}
abstract class FeedsRecyclerViewAdapter<T, VH : RecyclerView.ViewHolder?>: RecyclerView.Adapter<VH>() {
protected val feedContent: ArrayList<T> = arrayListOf()
protected lateinit var context: Context
override fun getItemCount(): Int = feedContent.size
open fun initializeWith(content: List<T>){
feedContent.clear()
feedContent.addAll(content)
notifyDataSetChanged()
}
}

View File

@ -0,0 +1,34 @@
package com.h.pixeldroid.fragments.feeds
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.h.pixeldroid.objects.Status
import kotlinx.android.synthetic.main.fragment_home.*
class HomeFragment : FeedFragment<Status, HomeRecyclerViewAdapter.ViewHolder>() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = super.onCreateView(inflater, container)
adapter = HomeRecyclerViewAdapter()
list.adapter = adapter
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
swipeRefreshLayout.setOnRefreshListener {
val call = pixelfedAPI.timelineHome("Bearer $accessToken")
doRequest(call)
}
val call = pixelfedAPI.timelineHome("Bearer $accessToken")
doRequest(call)
}
}

View File

@ -1,6 +1,5 @@
package com.h.pixeldroid.fragments
package com.h.pixeldroid.fragments.feeds
import android.content.Context
import android.graphics.Typeface
import android.util.DisplayMetrics
import androidx.recyclerview.widget.RecyclerView
@ -10,29 +9,20 @@ import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import com.h.pixeldroid.R
import com.h.pixeldroid.models.Post
import com.h.pixeldroid.objects.Status
import com.h.pixeldroid.utils.ImageConverter.Companion.setDefaultImage
import com.h.pixeldroid.utils.ImageConverter.Companion.setImageViewFromURL
import com.h.pixeldroid.utils.ImageConverter.Companion.setRoundImageFromURL
import java.util.ArrayList
/**
* [RecyclerView.Adapter] that can display a list of [Post]s
* [RecyclerView.Adapter] that can display a list of Posts
*/
class FeedRecyclerViewAdapter(
private val context : Context
) : RecyclerView.Adapter<FeedRecyclerViewAdapter.ViewHolder>() {
private val posts: ArrayList<Post> = ArrayList<Post>()
fun addPosts(newPosts : List<Post>) {
val size = posts.size
posts.addAll(newPosts)
notifyItemRangeInserted(size, newPosts.size)
}
class HomeRecyclerViewAdapter() : FeedsRecyclerViewAdapter<Status, HomeRecyclerViewAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(context)
val view = inflater.inflate(R.layout.post_fragment, parent, false)
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.post_fragment, parent, false)
context = view.context
return ViewHolder(view)
}
@ -40,7 +30,7 @@ class FeedRecyclerViewAdapter(
* Binds the different elements of the Post Model to the view holder
*/
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val post = posts[position]
val post = feedContent[position]
val metrics = DisplayMetrics()
//Limit the height of the different images
@ -72,7 +62,7 @@ class FeedRecyclerViewAdapter(
holder.nshares.setTypeface(null, Typeface.BOLD)
}
override fun getItemCount(): Int = posts.size
override fun getItemCount(): Int = feedContent.size
/**
* Represents the posts that will be contained within the feed

View File

@ -0,0 +1,44 @@
package com.h.pixeldroid.fragments.feeds
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.h.pixeldroid.R
import com.h.pixeldroid.objects.Notification
import kotlinx.android.synthetic.main.fragment_feed.*
/**
* A fragment representing a list of Items.
*/
class NotificationsFragment : FeedFragment<Notification, NotificationsRecyclerViewAdapter.ViewHolder>() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = super.onCreateView(inflater, container)
adapter = NotificationsRecyclerViewAdapter()
list.adapter = adapter
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
swipeRefreshLayout.setOnRefreshListener {
val call = pixelfedAPI.notifications("Bearer $accessToken", min_id="1")
doRequest(call)
}
val call = pixelfedAPI.notifications("Bearer $accessToken", min_id="1")
doRequest(call)
}
}

View File

@ -1,4 +1,4 @@
package com.h.pixeldroid.fragments
package com.h.pixeldroid.fragments.feeds
import android.content.Context
@ -16,17 +16,14 @@ import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import com.h.pixeldroid.PostActivity
import com.h.pixeldroid.R
import com.h.pixeldroid.models.Post
import com.h.pixeldroid.models.Post.Companion.POST_TAG
import com.h.pixeldroid.objects.Status.Companion.POST_TAG
import com.h.pixeldroid.objects.Notification
import kotlinx.android.synthetic.main.fragment_notifications.view.*
/**
* [RecyclerView.Adapter] that can display a [Notification]
*/
class NotificationsRecyclerViewAdapter: RecyclerView.Adapter<NotificationsRecyclerViewAdapter.ViewHolder>() {
private val notifications: ArrayList<Notification> = arrayListOf()
private lateinit var context: Context
class NotificationsRecyclerViewAdapter: FeedsRecyclerViewAdapter<Notification, NotificationsRecyclerViewAdapter.ViewHolder>() {
private val mOnClickListener: View.OnClickListener
@ -41,7 +38,7 @@ class NotificationsRecyclerViewAdapter: RecyclerView.Adapter<NotificationsRecycl
when (notification.type){
Notification.NotificationType.mention, Notification.NotificationType.favourite-> {
intent = Intent(context, PostActivity::class.java)
intent.putExtra(POST_TAG, Post(notification.status))
intent.putExtra(POST_TAG, notification.status)
}
Notification.NotificationType.reblog-> {
Toast.makeText(context,"Can't see shares yet, sorry!",Toast.LENGTH_SHORT).show()
@ -55,14 +52,9 @@ class NotificationsRecyclerViewAdapter: RecyclerView.Adapter<NotificationsRecycl
context.startActivity(intent)
}
fun initializeWith(newNotifications: List<Notification>){
notifications.clear()
notifications.addAll(newNotifications)
notifyDataSetChanged()
}
fun addNotifications(newNotifications: List<Notification>){
val oldSize = notifications.size
notifications.addAll(newNotifications)
val oldSize = feedContent.size
feedContent.addAll(newNotifications)
notifyItemRangeInserted(oldSize, newNotifications.size)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
@ -74,11 +66,11 @@ class NotificationsRecyclerViewAdapter: RecyclerView.Adapter<NotificationsRecycl
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val notification = notifications[position]
val notification = feedContent[position]
Glide.with(holder.mView).load(notification.account.avatar_static).apply(RequestOptions().circleCrop())
.placeholder(R.drawable.ic_default_user).into(holder.avatar)
val previewUrl = notification.status?.media_attachments?.get(0)?.preview_url
val previewUrl = notification.status?.media_attachments?.getOrNull(0)?.preview_url
if(!previewUrl.isNullOrBlank()){
Glide.with(holder.mView).load(previewUrl)
.placeholder(R.drawable.ic_picture_fallback).into(holder.photoThumbnail)
@ -125,7 +117,6 @@ class NotificationsRecyclerViewAdapter: RecyclerView.Adapter<NotificationsRecycl
return Pair(context.getString(format), context.getDrawable(drawable))
}
override fun getItemCount(): Int = notifications.size
inner class ViewHolder(val mView: View) : RecyclerView.ViewHolder(mView) {
val notificationType: TextView = mView.notification_type

View File

@ -1,86 +0,0 @@
package com.h.pixeldroid.models
import android.content.Context
import android.graphics.Typeface
import android.view.View
import android.widget.TextView
import androidx.core.content.ContextCompat.startActivity
import androidx.fragment.app.Fragment
import com.h.pixeldroid.R
import com.h.pixeldroid.objects.Status
import com.h.pixeldroid.utils.ImageConverter
import java.io.Serializable
class Post(private val status: Status?) : Serializable {
companion object {
const val POST_TAG = "postTag"
const val POST_FRAG_TAG = "postFragTag"
}
fun getPostUrl() : String? = status?.media_attachments?.get(0)?.url
fun getProfilePicUrl() : String? = status?.account?.avatar
fun getDescription() : CharSequence {
val description = status?.content as CharSequence
if(description.isEmpty()) {
return "No description"
}
return description
}
fun getUsername() : CharSequence {
var name = status?.account?.username
if (name.isNullOrEmpty()) {
name = status?.account?.display_name
}
return name!!
}
fun getUsernameDescription() : CharSequence {
return status?.account?.display_name ?: ""
}
fun getNLikes() : CharSequence {
val nLikes : Int = status?.favourites_count ?: 0
return "$nLikes Likes"
}
fun getNShares() : CharSequence {
val nShares : Int = status?.reblogs_count ?: 0
return "$nShares Shares"
}
fun setupPost(fragment: Fragment, rootView : View) {
//Setup username as a button that opens the profile
val username = rootView.findViewById<TextView>(R.id.username)
username.text = this.getUsername()
username.setTypeface(null, Typeface.BOLD)
val usernameDesc = rootView.findViewById<TextView>(R.id.usernameDesc)
usernameDesc.text = this.getUsernameDescription()
usernameDesc.setTypeface(null, Typeface.BOLD)
val description = rootView.findViewById<TextView>(R.id.description)
description.text = this.getDescription()
val nlikes = rootView.findViewById<TextView>(R.id.nlikes)
nlikes.text = this.getNLikes()
nlikes.setTypeface(null, Typeface.BOLD)
val nshares = rootView.findViewById<TextView>(R.id.nshares)
nshares.text = this.getNShares()
nshares.setTypeface(null, Typeface.BOLD)
//Setup post and profile images
ImageConverter.setImageViewFromURL(
fragment,
getPostUrl(),
rootView.findViewById(R.id.postPicture)
)
ImageConverter.setImageViewFromURL(
fragment,
getProfilePicUrl(),
rootView.findViewById(R.id.profilePic)
)
}
}

View File

@ -1,5 +1,11 @@
package com.h.pixeldroid.objects
import android.graphics.Typeface
import android.view.View
import android.widget.TextView
import androidx.fragment.app.Fragment
import com.h.pixeldroid.R
import com.h.pixeldroid.utils.ImageConverter
import java.io.Serializable
/*
@ -43,6 +49,77 @@ data class Status(
val pinned: Boolean
) : Serializable
{
companion object {
const val POST_TAG = "postTag"
const val POST_FRAG_TAG = "postFragTag"
}
fun getPostUrl() : String? = media_attachments?.getOrNull(0)?.url
fun getProfilePicUrl() : String? = account?.avatar
fun getDescription() : CharSequence {
val description = content as CharSequence
if(description.isEmpty()) {
return "No description"
}
return description
}
fun getUsername() : CharSequence {
var name = account?.username
if (name.isNullOrEmpty()) {
name = account?.display_name
}
return name!!
}
fun getUsernameDescription() : CharSequence {
return account?.display_name ?: ""
}
fun getNLikes() : CharSequence {
val nLikes : Int = favourites_count ?: 0
return "$nLikes Likes"
}
fun getNShares() : CharSequence {
val nShares : Int = reblogs_count ?: 0
return "$nShares Shares"
}
fun setupPost(fragment: Fragment, rootView : View) {
//Setup username as a button that opens the profile
val username = rootView.findViewById<TextView>(R.id.username)
username.text = this.getUsername()
username.setTypeface(null, Typeface.BOLD)
val usernameDesc = rootView.findViewById<TextView>(R.id.usernameDesc)
usernameDesc.text = this.getUsernameDescription()
usernameDesc.setTypeface(null, Typeface.BOLD)
val description = rootView.findViewById<TextView>(R.id.description)
description.text = this.getDescription()
val nlikes = rootView.findViewById<TextView>(R.id.nlikes)
nlikes.text = this.getNLikes()
nlikes.setTypeface(null, Typeface.BOLD)
val nshares = rootView.findViewById<TextView>(R.id.nshares)
nshares.text = this.getNShares()
nshares.setTypeface(null, Typeface.BOLD)
//Setup post and profile images
ImageConverter.setImageViewFromURL(
fragment,
getPostUrl(),
rootView.findViewById(R.id.postPicture)
)
ImageConverter.setImageViewFromURL(
fragment,
getProfilePicUrl(),
rootView.findViewById(R.id.profilePic)
)
}
enum class Visibility : Serializable {
public, unlisted, private, direct
}

View File

@ -8,7 +8,6 @@ import androidx.fragment.app.FragmentActivity
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import com.h.pixeldroid.R
import com.h.pixeldroid.models.Post
class ImageConverter {
companion object {

View File

@ -6,34 +6,58 @@
android:layout_height="match_parent"
tools:context=".LoginActivity">
<Button
android:id="@+id/connect_instance_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="36dp"
android:text="Connect"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/domainTextInputLayout" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/domainTextInputLayout"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:hint="Domain of your instance"
app:errorEnabled="true"
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.40">
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/editText"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textUri" />
</com.google.android.material.textfield.TextInputLayout>
android:gravity="center"
android:orientation="vertical">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/domainTextInputLayout"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:gravity="center"
android:hint="Domain of your instance"
app:errorEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textUri" />
<Button
android:id="@+id/connect_instance_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="36dp"
android:text="Connect" />
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:id="@+id/progressLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<ProgressBar
style="?android:attr/progressBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -4,7 +4,12 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".fragments.HomeFragment">
tools:context=".fragments.feeds.HomeFragment">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/feedList"
@ -16,10 +21,11 @@
app:layoutManager="LinearLayoutManager"
tools:listitem="@layout/post_fragment" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"/>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</FrameLayout>

View File

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
<androidx.recyclerview.widget.RecyclerView
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/list"
android:name="com.h.pixeldroid.fragments.NotificationsFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager"
tools:context=".fragments.NotificationsFragment"
tools:listitem="@layout/fragment_notifications" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

View File

@ -1,6 +1,5 @@
package com.h.pixeldroid
import com.h.pixeldroid.models.Post
import com.h.pixeldroid.objects.*
import org.junit.Assert
import org.junit.Test
@ -26,45 +25,42 @@ class PostUnitTest {
tags= listOf(Tag(name="hiking", url="https://pixelfed.de/discover/tags/hiking", history=null), Tag(name="nature", url="https://pixelfed.de/discover/tags/nature", history=null), Tag(name="rotavicentina", url="https://pixelfed.de/discover/tags/rotavicentina", history=null)),
emojis= emptyList(), reblogs_count=0, favourites_count=0, replies_count=0, url="https://pixelfed.de/p/Miike/140364967936397312",
in_reply_to_id=null, in_reply_to_account=null, reblog=null, poll=null, card=null, language=null, text=null, favourited=false, reblogged=false, muted=false, bookmarked=false, pinned=false)
private val post = Post(status)
@Test
fun getPostUrlReturnsAValidURL() = Assert.assertNotNull(post.getPostUrl())
fun getPostUrlReturnsAValidURL() = Assert.assertNotNull(status.getPostUrl())
@Test
fun getProfilePicUrlReturnsAValidURL() = Assert.assertNotNull(post.getProfilePicUrl())
fun getProfilePicUrlReturnsAValidURL() = Assert.assertNotNull(status.getProfilePicUrl())
@Test
fun getDescriptionReturnsDefaultIfEmpty() {
val emptyDescStatus = status.copy(content = "")
val emptyDescPost = Post(emptyDescStatus)
Assert.assertEquals( "No description", emptyDescPost.getDescription())
Assert.assertEquals( "No description", emptyDescStatus.getDescription())
}
@Test
fun getDescriptionReturnsAValidDesc() = Assert.assertNotNull(post.getDescription())
fun getDescriptionReturnsAValidDesc() = Assert.assertNotNull(status.getDescription())
@Test
fun getDescriptionReturnsACorrectDesc() = Assert.assertEquals(status.content, post.getDescription())
fun getDescriptionReturnsACorrectDesc() = Assert.assertEquals(status.content, status.getDescription())
@Test
fun getUsernameReturnsACorrectName() = Assert.assertEquals(status.account.username, post.getUsername())
fun getUsernameReturnsACorrectName() = Assert.assertEquals(status.account.username, status.getUsername())
@Test
fun getUsernameReturnsOtherNameIfUsernameIsNull() {
val emptyDescStatus = status.copy(account = status.account.copy(username = ""))
val spePost = Post(emptyDescStatus)
Assert.assertEquals(status.account.display_name, spePost.getUsername())
Assert.assertEquals(status.account.display_name, emptyDescStatus.getUsername())
}
@Test
fun getNLikesReturnsCorrectFormat() {
Assert.assertEquals("${status.favourites_count} Likes", post.getNLikes())
Assert.assertEquals("${status.favourites_count} Likes", status.getNLikes())
}
@Test
fun getNSharesReturnsCorrectFormat() {
Assert.assertEquals("${status.reblogs_count} Shares", post.getNShares())
Assert.assertEquals("${status.reblogs_count} Shares", status.getNShares())
}
}