Skip to content

Commit

Permalink
Merge pull request #4 from ukrainefield/feature/bookmarks
Browse files Browse the repository at this point in the history
Feature/bookmarks
  • Loading branch information
GewoonJaap authored Mar 11, 2022
2 parents 9012777 + aa34878 commit 110833b
Show file tree
Hide file tree
Showing 13 changed files with 288 additions and 9 deletions.
10 changes: 5 additions & 5 deletions app/.idea/deploymentTargetDropDown.xml

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

3 changes: 3 additions & 0 deletions app/.idea/misc.xml

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

1 change: 1 addition & 0 deletions app/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,6 @@ dependencies {
implementation 'com.github.piasy:GlideImageViewFactory:1.8.1'
implementation 'com.google.firebase:firebase-crashlytics:18.2.8'
implementation 'androidx.preference:preference:1.1.0'
implementation 'com.google.code.gson:gson:2.9.0'

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package nl.gardensnakes.ukrainefield

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.firebase.analytics.FirebaseAnalytics
import nl.gardensnakes.ukrainefield.data.remote.SavedPreferences
import nl.gardensnakes.ukrainefield.helper.BookmarkHelper
import nl.gardensnakes.ukrainefield.view.adapter.FeedCardAdapter

class BookmarkFragment : Fragment() {

private lateinit var feedRecyclerView: RecyclerView
private lateinit var noBookmarksText: TextView

private lateinit var feedCardAdapter: FeedCardAdapter
private var useProxyServer: Boolean = false
private lateinit var mFirebaseAnalytics: FirebaseAnalytics

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_bookmark, container, false)

mFirebaseAnalytics = FirebaseAnalytics.getInstance(view.context);

useProxyServer = SavedPreferences.useProxyServer(requireContext())
feedRecyclerView = view.findViewById(R.id.bookmark_recycler_view)
noBookmarksText = view.findViewById(R.id.bookmark_no_bookmark_text)

val bookmarkedItems = BookmarkHelper().getAll(view.context)

if(bookmarkedItems == null || bookmarkedItems.isEmpty()){
noBookmarksText.visibility = View.VISIBLE
feedRecyclerView.visibility = View.GONE
}
else {
noBookmarksText.visibility = View.GONE
feedRecyclerView.visibility = View.VISIBLE
feedCardAdapter = FeedCardAdapter(bookmarkedItems.sortedByDescending { it.epochTime}, true)
feedRecyclerView.adapter = feedCardAdapter
feedRecyclerView.layoutManager = LinearLayoutManager(view.context);
}

return view
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ class MainActivity : AppCompatActivity() {
R.id.ukraine_map -> {
fragment = MapFragment()
}
R.id.bookmarks -> {
fragment = BookmarkFragment()
}
R.id.settings -> {
fragment = SettingsFragment()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package nl.gardensnakes.ukrainefield.helper

import android.content.Context
import android.util.Log
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import nl.gardensnakes.ukrainefield.data.remote.dto.feed.FeedMessageResponse
import java.io.*

class BookmarkHelper {
private var bookmarkedFeed: ArrayList<FeedMessageResponse>? = null

fun bookmark(feedItem: FeedMessageResponse, context: Context) {
val feedMessages = getAll(context) as ArrayList<FeedMessageResponse>

val found = feedMessages.firstOrNull {
it.messageURL == feedItem.messageURL
}

if(found == null) {
feedMessages.add(feedItem)
} else {
feedMessages.remove(found)
}

val json = extractToJson(feedMessages);

if(json != null) saveToJsonFile(json, context)
}


fun isFavorite(messageUrl: String, context: Context): Boolean {
return getAll(context)?.any {
it.messageURL == messageUrl
} ?: false
}

fun getAll(context: Context?): List<FeedMessageResponse>? {
return if(bookmarkedFeed != null) {
return bookmarkedFeed
} else {
context?.let {
readJsonFile(it)
}?.let {
extractToBookmark(it)
}
}
}

private fun extractToBookmark(videos: String): List<FeedMessageResponse>? {
val listOfBookmarks = Gson().fromJson<List<FeedMessageResponse>>(
videos,
object : TypeToken<ArrayList<FeedMessageResponse>>() {}.type
) ?: ArrayList(0)

this.bookmarkedFeed = listOfBookmarks as ArrayList<FeedMessageResponse>

return listOfBookmarks
}

private fun extractToJson(bookmarks: List<FeedMessageResponse>): String? {
return Gson().toJson(
bookmarks,
List::class.java
)
}

private fun saveToJsonFile(json: String, context: Context) {
try {
val outputStreamWriter = OutputStreamWriter(
context.openFileOutput(
"bookmarks.txt",
Context.MODE_PRIVATE
)
)

outputStreamWriter.write(json)
outputStreamWriter.close()
} catch (e: IOException) {
Log.e("Exception", "File write failed: $e")
}
}

private fun readJsonFile(context: Context): String {
var ret = ""

try {
val inputStream: InputStream? = context.openFileInput("bookmarks.txt")
if (inputStream != null) {
val inputStreamReader = InputStreamReader(inputStream)
val bufferedReader = BufferedReader(inputStreamReader)
var receiveString: String? = ""
val stringBuilder = StringBuilder()
while (bufferedReader.readLine().also { receiveString = it } != null) {
stringBuilder.append("\n").append(receiveString)
}
inputStream.close()
ret = stringBuilder.toString()
}
} catch (e: FileNotFoundException) {
Log.e("BookmarkHelper", "File not found: $e")
} catch (e: IOException) {
Log.e("BookmarkHelper", "Can not read file: $e")
}

return ret
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ import nl.gardensnakes.ukrainefield.MediaDetailActivity
import nl.gardensnakes.ukrainefield.R
import nl.gardensnakes.ukrainefield.data.remote.HttpRoutes
import nl.gardensnakes.ukrainefield.data.remote.dto.feed.FeedMessageResponse
import nl.gardensnakes.ukrainefield.helper.BookmarkHelper
import nl.gardensnakes.ukrainefield.helper.PreferenceHelper
import nl.gardensnakes.ukrainefield.helper.TimeHelper
import java.lang.Exception


class FeedCardAdapter(private val mList: List<FeedMessageResponse>) :
class FeedCardAdapter(private var mList: List<FeedMessageResponse>, private val deleteOnUnBookmark: Boolean = false) :
RecyclerView.Adapter<FeedCardAdapter.ViewHolder>() {

lateinit var context: Context
Expand All @@ -42,6 +44,7 @@ class FeedCardAdapter(private val mList: List<FeedMessageResponse>) :
override fun onBindViewHolder(holder: ViewHolder, position: Int) {

val feedData = mList[position]
val bookmarkHelper = BookmarkHelper()

resetView(holder)

Expand Down Expand Up @@ -69,6 +72,8 @@ class FeedCardAdapter(private val mList: List<FeedMessageResponse>) :
holder.postedAtText.text =
"${context.getString(R.string.posted_at)} ${TimeHelper.epochToTimeString(feedData.epochTime.toLong())}"

updateBookmarkText(bookmarkHelper, feedData.messageURL ?: "", holder, position)

if (feedData.videos.isEmpty() && feedData.images.isEmpty()) {
holder.imageSlide.visibility = View.GONE
} else if (feedData.videos.isNotEmpty()) {
Expand Down Expand Up @@ -115,13 +120,36 @@ class FeedCardAdapter(private val mList: List<FeedMessageResponse>) :
startActivity(context, browserIntent, null)
}

holder.bookmarkButton.setOnClickListener {
bookmarkHelper.bookmark(feedData, context)
updateBookmarkText(bookmarkHelper, feedData.messageURL ?: "", holder, position)
}

}

// return the number of the items in the list
override fun getItemCount(): Int {
return mList.size
}

private fun updateBookmarkText(bookmarkHelper: BookmarkHelper, messageUrl: String, holder: ViewHolder, position: Int){
var isBookmarked = bookmarkHelper.isFavorite(messageUrl, context)
if(isBookmarked){
holder.bookmarkButton.text = context.getString(R.string.remove_bookmark)
}
else{
holder.bookmarkButton.text = context.getString(R.string.bookmark)
if(deleteOnUnBookmark){
try {
notifyItemRemoved(position)
notifyItemRangeChanged(position, mList.size)
mList = BookmarkHelper().getAll(context) ?: emptyList()
mList = mList.sortedByDescending { it.epochTime }
} catch(e: Exception){}
}
}
}

private fun resetView(holder: ViewHolder) {
holder.videoView.stopPlayback()
holder.videoView.visibility = View.GONE
Expand All @@ -147,5 +175,6 @@ class FeedCardAdapter(private val mList: List<FeedMessageResponse>) :
val shareView: Button = itemView.findViewById(R.id.feed_card_share_button)
val browserButtonView: Button = itemView.findViewById(R.id.feed_card_browser_button)
val videoView: VideoView = itemView.findViewById(R.id.feed_card_video)
var bookmarkButton: Button = ItemView.findViewById(R.id.feed_card_bookmark_button)
}
}
10 changes: 10 additions & 0 deletions app/app/src/main/res/drawable/ic_baseline_bookmark_24.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="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M17,3H7c-1.1,0 -1.99,0.9 -1.99,2L5,21l7,-3 7,3V5c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>
10 changes: 10 additions & 0 deletions app/app/src/main/res/drawable/ic_baseline_no_bookmark_24.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="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M17,3L7,3c-1.1,0 -1.99,0.9 -1.99,2L5,21l7,-3 7,3L19,5c0,-1.1 -0.9,-2 -2,-2zM17,18l-5,-2.18L7,18L7,5h10v13z"/>
</vector>
15 changes: 15 additions & 0 deletions app/app/src/main/res/layout/feed_card.xml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,21 @@
android:id="@+id/feed_card_browser_button"
/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:text="@string/bookmark"
app:icon="@drawable/ic_baseline_no_bookmark_24"
style="?attr/borderlessButtonStyle"
android:id="@+id/feed_card_bookmark_button"
/>
</LinearLayout>

</LinearLayout>

Expand Down
32 changes: 32 additions & 0 deletions app/app/src/main/res/layout/fragment_bookmark.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".BookmarkFragment">

<TextView
android:id="@+id/bookmark_no_bookmark_text"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/roboto_medium"
android:text="Nothing bookmarked yet. \nBookmark some messages"
android:textAlignment="center"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />


<androidx.recyclerview.widget.RecyclerView
android:id="@+id/bookmark_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:itemCount="5"
tools:listitem="@layout/feed_card" />

</androidx.constraintlayout.widget.ConstraintLayout>
Loading

0 comments on commit 110833b

Please sign in to comment.