Skip to content

Commit

Permalink
clean-up
Browse files Browse the repository at this point in the history
  • Loading branch information
s1g53gv committed Dec 3, 2024
1 parent 2addb86 commit 2d8a22e
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 70 deletions.
18 changes: 18 additions & 0 deletions .idea/deploymentTargetSelector.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 15 additions & 13 deletions app/src/main/java/it/bz/noi/community/data/models/News.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import it.bz.noi.community.utils.Utils
import kotlinx.parcelize.Parcelize
import java.util.*

private const val ID_TAG_IMPORTANT = "important" // ID of the "important" tag

@Keep
@Parcelize
data class News(
Expand All @@ -27,7 +29,7 @@ data class News(
@SerializedName("ODHTags")
val tags: List<Tag>? = null,
@SerializedName("Highlight")
val highlighted: Boolean = false,
val isHighlighted: Boolean = false,
) : Parcelable

@Keep
Expand Down Expand Up @@ -68,21 +70,21 @@ data class NewsImage(
val url: String? = null
) : Parcelable

fun News.getDetail(): Detail? {
return detail[Utils.getAppLanguage()]
}
/**
* Get the localized detail for the current app language.
*/
fun News.getLocalizedDetail(): Detail? = detail[Utils.getAppLanguage()]

fun News.getContactInfo(): ContactInfo? {
return contactInfo?.let {
it[Utils.getAppLanguage()]
}
}
/**
* Get the localized contact info for the current app language.
*/
fun News.getLocalizedContactInfo(): ContactInfo? = contactInfo?.get(Utils.getAppLanguage())

// FIXME -> WIP
fun News.hasImportantFlag(): Boolean {
val isImportant = tags != null && tags.filter { it.id == "important" }.isNotEmpty()
return isImportant || highlighted
}
/**
* Whether the news is important, that is, it has the "important" tag.
*/
val News.isImportant get(): Boolean = tags?.any { it.id == ID_TAG_IMPORTANT } ?: false

data class NewsResponse(
@SerializedName("TotalResults")
Expand Down
23 changes: 18 additions & 5 deletions app/src/main/java/it/bz/noi/community/data/models/NewsParams.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

package it.bz.noi.community.data.models

import it.bz.noi.community.utils.DateUtils
import it.bz.noi.community.utils.Utils
import java.util.Date

data class NewsParams(
var startDate: String,
var pageSize: Int = 10,
Expand All @@ -12,8 +16,17 @@ data class NewsParams(
var highlight: Boolean = false
)

fun NewsParams.getRawFilter(): String {
if (highlight)
return "eq(Highlight,\"true\")"
return "or(eq(Highlight,\"false\"),isnull(Highlight))"
}
/**
* Factory for creating [NewsParams].
*/
fun NewsParams(nextPageNumber: Int, pageSize: Int, from: Date, moreHighlights: Boolean) =
NewsParams(
startDate = DateUtils.parameterDateFormatter().format(from),
pageSize = pageSize,
pageNumber = nextPageNumber,
language = Utils.getAppLanguage(),
highlight = moreHighlights
)

fun NewsParams.getRawFilter(): String =
if (highlight) "eq(Highlight,\"true\")" else "or(eq(Highlight,\"false\"),isnull(Highlight))"
11 changes: 6 additions & 5 deletions app/src/main/java/it/bz/noi/community/ui/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.*
import java.util.*

private const val PAGE_SIZE = 10 // How many news to load at once

/**
* Factory for creating the MainViewModel
*/
Expand Down Expand Up @@ -242,7 +244,7 @@ class MainViewModel(
filters= filterRepo.loadFilters()
}

if (filters != null && filters.isNotEmpty())
if (filters.isNotEmpty())
emit(Resource.success(data = filters))
else
emit(Resource.error(data = null, message = "Filter loading: error occurred!"))
Expand All @@ -256,8 +258,8 @@ class MainViewModel(
loadNews()
}.stateIn(viewModelScope, SharingStarted.Lazily, PagingData.empty())

private fun loadNews(): Flow<PagingData<News>> = Pager(PagingConfig(pageSize = NewsPagingSource.PAGE_ITEMS)) {
NewsPagingSource(mainRepository)
private fun loadNews(): Flow<PagingData<News>> = Pager(PagingConfig(pageSize = PAGE_SIZE)) {
NewsPagingSource(PAGE_SIZE, mainRepository)
}.flow.cachedIn(viewModelScope)

fun refreshNews() {
Expand All @@ -267,9 +269,8 @@ class MainViewModel(
}

object NewsTickerFlow {
val ticker = MutableSharedFlow<Unit>(replay = 1).apply {
private val ticker = MutableSharedFlow<Unit>(replay = 1).apply {
tryEmit(Unit)
}
fun tick() = ticker.tryEmit(Unit)
}

Original file line number Diff line number Diff line change
Expand Up @@ -32,26 +32,31 @@ import it.bz.noi.community.data.api.ApiHelper
import it.bz.noi.community.data.api.RetrofitBuilder
import it.bz.noi.community.data.models.News
import it.bz.noi.community.data.models.NewsImage
import it.bz.noi.community.data.models.getContactInfo
import it.bz.noi.community.data.models.getDetail
import it.bz.noi.community.data.models.getLocalizedContactInfo
import it.bz.noi.community.data.models.getLocalizedDetail
import it.bz.noi.community.databinding.FragmentNewsDetailsBinding
import it.bz.noi.community.databinding.VhHorizontalImageBinding
import it.bz.noi.community.utils.Status
import kotlinx.coroutines.Dispatchers
import java.text.DateFormat


class NewsDetailsFragment: Fragment() {
class NewsDetailsFragment : Fragment() {

private var _binding: FragmentNewsDetailsBinding? = null
private val binding get() = _binding!!

private val viewModel: NewsDetailViewModel by viewModels(factoryProducer = {
NewsDetailViewModelFactory(apiHelper = ApiHelper(RetrofitBuilder.opendatahubApiService, RetrofitBuilder.communityApiService),
this@NewsDetailsFragment)
NewsDetailViewModelFactory(
apiHelper = ApiHelper(
RetrofitBuilder.opendatahubApiService,
RetrofitBuilder.communityApiService
),
this@NewsDetailsFragment
)
})

private val df = DateFormat.getDateInstance(DateFormat.SHORT)
private val dateFormat = DateFormat.getDateInstance(DateFormat.SHORT)

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Expand Down Expand Up @@ -82,16 +87,18 @@ class NewsDetailsFragment: Fragment() {
super.onViewCreated(view, savedInstanceState)

viewModel.newsFlow.asLiveData(Dispatchers.Main).observe(viewLifecycleOwner) {
when(it.status) {
when (it.status) {
Status.SUCCESS -> {
binding.newsLoader.isVisible = false
val news = it.data!!
loadNewsData(news)
}

Status.ERROR -> {
binding.newsLoader.isVisible = false
Toast.makeText(requireContext(), it.message, Toast.LENGTH_LONG).show()
}

Status.LOADING -> {
binding.newsLoader.isVisible = true
}
Expand All @@ -103,22 +110,23 @@ class NewsDetailsFragment: Fragment() {
private fun loadNewsData(news: News) {
setTransitionNames(news.id)

binding.date.text = df.format(news.date)
binding.date.text = dateFormat.format(news.date)

news.getDetail()?.let { detail ->
news.getLocalizedDetail()?.let { detail ->
(requireActivity() as AppCompatActivity).supportActionBar?.title = detail.title

binding.title.text = detail.title
binding.shortText.text = detail.abstract
binding.longText.text = detail.text?.let{ Html.fromHtml(it, Html.FROM_HTML_MODE_LEGACY) }
binding.longText.text =
detail.text?.let { Html.fromHtml(it, Html.FROM_HTML_MODE_LEGACY) }
binding.longText.movementMethod = LinkMovementMethod.getInstance()
}

var isExternalLink = false
var isEmail = false
val contactInfo = news.getContactInfo()
val contactInfo = news.getLocalizedContactInfo()
if (contactInfo == null) {
binding.publisher.text = "N/D"
binding.publisher.text = "N/D" //TODO: localize this
} else {
binding.publisher.text = contactInfo.publisher

Expand Down Expand Up @@ -169,9 +177,10 @@ class NewsDetailsFragment: Fragment() {
binding.askQuestion.isVisible = isEmail
binding.footer.isVisible = isExternalLink || isEmail

if (news.images != null && news.images.isNotEmpty()) {
if (!news.images.isNullOrEmpty()) {
binding.images.isVisible = true
binding.images.layoutManager = LinearLayoutManager(binding.root.context, LinearLayoutManager.HORIZONTAL, false)
binding.images.layoutManager =
LinearLayoutManager(binding.root.context, LinearLayoutManager.HORIZONTAL, false)
binding.images.adapter = NewsImagesAdapter(news.images)
} else {
binding.images.isVisible = false
Expand All @@ -190,33 +199,35 @@ class NewsDetailsFragment: Fragment() {
private fun writeEmail(receiverAddress: String) {
val intent = Intent(Intent.ACTION_SENDTO).apply {
data = Uri.parse("mailto:") // only email apps should handle this
putExtra(Intent.EXTRA_EMAIL, Array(1) {receiverAddress})
putExtra(Intent.EXTRA_EMAIL, Array(1) { receiverAddress })
}
if (intent.resolveActivity(requireContext().packageManager) != null) {
startActivity(intent)
}
}

private fun openExternalLink(url: String) {
val intent = Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse(url)
}
val intent =
Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, Intent.CATEGORY_APP_BROWSER).apply {
data = Uri.parse(url)
}
if (intent.resolveActivity(requireContext().packageManager) != null) {
startActivity(intent)
}
}

}

/**
* Adapter used to populate the image gallery of news detail
*/
class NewsImagesAdapter(private val images: List<NewsImage>) : RecyclerView.Adapter<NewsImagesAdapter.NewsImageViewHolder>() {
class NewsImagesAdapter(private val images: List<NewsImage>) :
RecyclerView.Adapter<NewsImagesAdapter.NewsImageViewHolder>() {

/**
* View holder of a single picture
*/
inner class NewsImageViewHolder(private val binding: VhHorizontalImageBinding) : RecyclerView.ViewHolder(binding.root) {
inner class NewsImageViewHolder(private val binding: VhHorizontalImageBinding) :
RecyclerView.ViewHolder(binding.root) {

fun bind(image: NewsImage) {
Glide
Expand All @@ -228,7 +239,13 @@ class NewsImagesAdapter(private val images: List<NewsImage>) : RecyclerView.Adap
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NewsImageViewHolder {
return NewsImageViewHolder(VhHorizontalImageBinding.inflate(LayoutInflater.from(parent.context), parent, false))
return NewsImageViewHolder(
VhHorizontalImageBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}

override fun onBindViewHolder(holder: NewsImageViewHolder, position: Int) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ import com.bumptech.glide.Glide
import it.bz.noi.community.data.api.ApiHelper
import it.bz.noi.community.data.api.RetrofitBuilder
import it.bz.noi.community.data.models.News
import it.bz.noi.community.data.models.getContactInfo
import it.bz.noi.community.data.models.getDetail
import it.bz.noi.community.data.models.hasImportantFlag
import it.bz.noi.community.data.models.getLocalizedContactInfo
import it.bz.noi.community.data.models.getLocalizedDetail
import it.bz.noi.community.data.models.isImportant
import it.bz.noi.community.data.repository.JsonFilterRepository
import it.bz.noi.community.databinding.FragmentNewsBinding
import it.bz.noi.community.databinding.VhNewsBinding
Expand Down Expand Up @@ -197,14 +197,16 @@ class NewsVH(private val binding: VhNewsBinding, detailListener: NewsDetailListe
fun bind(news: News) {
this.news = news
binding.date.text = df.format(news.date)
binding.importantTag.isVisible = news.hasImportantFlag()
if (news.highlighted) // FIXME -> WIP
binding.importantTag.isVisible = news.isImportant || news.isHighlighted
if (news.isHighlighted) { // FIXME -> WIP
binding.importantTag.text = "TMP PINNATO"
news.getDetail()?.let { detail ->
}

news.getLocalizedDetail()?.let { detail ->
binding.title.text = detail.title
binding.shortText.text = detail.abstract
}
val contactInfo = news.getContactInfo()
val contactInfo = news.getLocalizedContactInfo()
if (contactInfo == null) {
binding.publisher.text = "N/D"
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,20 @@ import it.bz.noi.community.utils.DateUtils
import it.bz.noi.community.utils.Utils
import java.util.*

class NewsPagingSource(private val mainRepository: MainRepository) :
PagingSource<Int, News>() {

companion object {
private const val TAG = "NewsPagingSource"
const val PAGE_ITEMS = 10
}
private const val TAG = "NewsPagingSource"

class NewsPagingSource(private val pageSize: Int, private val mainRepository: MainRepository) :
PagingSource<Int, News>() {

private val startDate = Date()

private var moreHighlight = true

override suspend fun load(params: LoadParams<Int>): LoadResult<Int, News> {
// Start refresh at page 1 if undefined.
val nextPageNumber = params.key ?: 1

val newsParams = getNewsParams(nextPageNumber)
val newsParams = NewsParams(nextPageNumber, pageSize, startDate, moreHighlight)

return try {
val newsResponse = mainRepository.getNews(newsParams)
Expand All @@ -42,7 +40,12 @@ class NewsPagingSource(private val mainRepository: MainRepository) :
if (moreHighlight && nextKey == null) {
moreHighlight = false

val notHighlightedNewsParams = getNewsParams(nextPageNumber)
val notHighlightedNewsParams = NewsParams(
nextPageNumber,
pageSize,
startDate,
false
)
val notHighlightedNewsResponse = mainRepository.getNews(notHighlightedNewsParams)
news.addAll(notHighlightedNewsResponse.news)

Expand All @@ -59,17 +62,8 @@ class NewsPagingSource(private val mainRepository: MainRepository) :
FirebaseCrashlytics.getInstance().recordException(ex)
LoadResult.Error(ex)
}

}

private fun getNewsParams(nextPageNumber: Int) = NewsParams(
startDate = DateUtils.parameterDateFormatter().format(startDate),
pageSize = PAGE_ITEMS,
pageNumber = nextPageNumber,
language = Utils.getAppLanguage(),
highlight = moreHighlight
)

override fun getRefreshKey(state: PagingState<Int, News>): Int? {
// Try to find the page key of the closest page to anchorPosition, from
// either the prevKey or the nextKey, but you need to handle nullability
Expand Down

0 comments on commit 2d8a22e

Please sign in to comment.