attachments collection
github-actions opened this issue · 1 comments
github-actions commented
attachments collection
import java.util.*
class HomeFragment : Fragment() {
private lateinit var changesAdapter: CompactChangesAdapter
private lateinit var changesRecycler: RecyclerView
private lateinit var tasks: MutableList<Tasks.TaskData>
private lateinit var tasksRecycler: RecyclerView
private lateinit var tasksTitle: TextView
private lateinit var tasksRecyclerLayout: LinearLayout
private lateinit var posts: MutableList<CompactPostsAdapter.PostData>
private lateinit var unreadPostsRecycler: RecyclerView
private lateinit var messagesLayout: LinearLayout
private lateinit var messagesAdapter: ConversationsAdapter
/**
* Update tasks title to reflect the current number of undone tasks
* Also hide or show recycler layout if needed
*/
fun updateTasksTitle() {
// Update title
if (tasks.size == 0 || tasksRecycler.adapter?.itemCount == 0) {
// If tasks list is now empty, update title to display everything is done
tasksTitle.setText(R.string.tasks_filter_none_undone)
// Hide recycler layout as it would just show an empty border
tasksRecyclerLayout.visibility = View.GONE
} else {
// Else update the title to show the number of undone tasks
tasksTitle.text = SphPlanner.appContext().resources.getQuantityString(
R.plurals.tasks_personalized_title_count,
tasks.size,
tasks.size)
// Make sure tasks recycler layout is visible
tasksRecyclerLayout.visibility = View.VISIBLE
}
}
// Refresh whenever the broadcast "uichange" is received
private val uichangeReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// Update posts list with new unread posts
if (intent.getStringExtra("content") == "posts") {
// If there wasn't any post or any task before but now is,
// it's easier to recreate the fragment
if (!::unreadPostsRecycler.isInitialized
|| unreadPostsRecycler.adapter == null
|| tasksRecycler.adapter == null) {
view?.post {
parentFragmentManager.beginTransaction()
.replace(R.id.nav_host_fragment, HomeFragment())
.setReorderingAllowed(true) //Optimizing state changes for better transitions
.commit()
}
return
}
// Add all new posts to the top of the posts list
// Removed posts will not be removed
val unreadPosts = PostsDb.getInstance().getData("unread = 1")
for (post in unreadPosts) {
if (!posts.contains(post)) {
posts.add(0, post)
unreadPostsRecycler.adapter?.notifyItemInserted(0)
unreadPostsRecycler.adapter?.notifyItemRemoved(3)
}
}
// Add all new tasks to the top of the tasks list
val unreadTasks = TasksDb.getInstance().getUndoneData(false)
for (task in unreadTasks) {
if (tasks.indexOfFirst { it.id == task.id } == -1) {
tasks.add(0, task)
tasksRecycler.adapter?.notifyItemInserted(0)
tasksRecycler.adapter?.notifyItemRemoved(5)
}
}
// Update tasks title
updateTasksTitle()
}
// Update tasks and posts list when a task is done
else if (intent.getStringExtra("content") == "taskDone"
&& ::tasks.isInitialized) {
val taskId = intent.getStringExtra("taskId")
val postId = intent.getStringExtra("postId")
// If tasks list contains this, notify tasks aapter, else add it
val taskIndex = tasks.indexOfFirst { it.id == taskId }
if (taskIndex != -1) {
// Remove this task from the recycler
tasks.removeAt(taskIndex)
tasksRecycler.adapter?.notifyItemRemoved(taskIndex)
} else if (!intent.getBooleanExtra("isDone", true)) {
val taskToAdd = TasksDb.getInstance().getDataById(taskId, false)
if (taskToAdd != null) {
// Add task to the top of the list if it is not done and wasn't there before
tasks.add(0, taskToAdd)
tasksRecycler.adapter?.notifyItemInserted(0)
tasksRecycler.adapter?.notifyItemRemoved(5)
}
}
// Update title
updateTasksTitle()
if (postId != null) {
// If posts list contains this, notify it
val postIndex = posts.indexOfFirst { it.id == postId }
if (postIndex != -1) unreadPostsRecycler.adapter?.notifyItemChanged(postIndex)
}
} else if (intent.getStringExtra("content") == "changes" &&
FunctionTilesDb.getInstance().supports(FunctionTile.FEATURE_CHANGES)
&& ::changesAdapter.isInitialized) {
// Update changes ui
changesAdapter.changes = ChangesDb.instance!!.getFavorites()
changesAdapter.notifyDataSetChanged()
// Make sure the layout is visible
if (changesAdapter.changes.isNotEmpty())
changesRecycler.visibility = View.VISIBLE
} else if (intent.getStringExtra("content") == "messages" &&
::messagesAdapter.isInitialized &&
Firebase.remoteConfig.getBoolean("messages_enabled")) {
// Update messages
// Get the updated conversation
val updateId = intent.getStringExtra("id")
val updatedInfo = ConversationsDb()
.getConversationInfo(
"archived=0 AND conversation_id=\"$updateId\"")
.firstOrNull()
if (updatedInfo != null) {
if (intent.getStringExtra("type") == "new") {
// New conversation, just add it to the top of the list
messagesAdapter.conversations.add(0, updatedInfo)
messagesAdapter.notifyItemInserted(0)
// Make sure the layout is visible
messagesLayout.visibility = View.VISIBLE
} else if (intent.getStringExtra("type") == "metachanged") {
// Updated conversation, find and update it in the list
// Move it to the top while we're at it
val index = messagesAdapter.conversations.indexOfFirst { it.id == updateId }
if (index != -1) {
// Remove current position and push to list
messagesAdapter.conversations.removeAt(index)
messagesAdapter.conversations.add(0, updatedInfo)
// Notify item moved to top and changed
messagesAdapter.notifyItemMoved(index, 0)
messagesAdapter.notifyItemChanged(0)
}
}
}
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Register to receive messages.
LocalBroadcastManager.getInstance(requireContext()).registerReceiver(uichangeReceiver,
IntentFilter("uichange"))
}
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_home, container, false)
// Set random greeting as action bar title, once per app start, or after 30 minutes
if (SphPlanner.randomGreeting == null || Date().time - SphPlanner.randomGreetingTime > 30 * 60 * 1000) {
SphPlanner.randomGreeting = Utility.getGreeting()
SphPlanner.randomGreetingTime = Date().time
}
(activity as AppCompatActivity).supportActionBar?.title = SphPlanner.randomGreeting
/*
* Timetable
*/
val timetableLayout = view.findViewById<LinearLayout>(R.id.timetableLayout)
val timetable = view.findViewById<FragmentContainerView>(R.id.timetableFragment)
if (FunctionTilesDb.getInstance().supports(FunctionTile.FEATURE_TIMETABLE)) {
parentFragmentManager.beginTransaction()
.add(R.id.timetableFragment, TimetableViewFragment())
.setReorderingAllowed(true) //Optimizing state changes for better transitions
.commit()
timetableLayout.setOnClickListener {
Navigation.findNavController(requireActivity(), R.id.nav_host_fragment)
.navigate(R.id.timetableFromHomeAction, null, null,
FragmentNavigatorExtras(timetable to "timetable"))
}
} else timetableLayout.visibility = View.GONE
/*
* Messages
*/
messagesLayout = view.findViewById(R.id.messagesLayout)
val messagesRecycler = view.findViewById<RecyclerView>(R.id.messagesRecycler)
if (FunctionTilesDb.getInstance().supports(FunctionTile.FEATURE_MESSAGES)
&& FirebaseRemoteConfig.getInstance().getBoolean("messages_enabled")) {
// Get info for unread conversations
val unreadMessages = ConversationsDb().getConversationInfo(
"conversations.unread=1").toMutableList()
messagesAdapter = ConversationsAdapter(unreadMessages, requireActivity(), compactMode = true)
messagesRecycler.adapter = messagesAdapter
// If no unread messages are to be displayed, hide the layout
if (unreadMessages.isEmpty()) {
messagesLayout.visibility = View.GONE
}
// Navigate to fragments tab
messagesLayout.setOnClickListener {
Navigation.findNavController(requireActivity(), R.id.nav_host_fragment)
.navigate(R.id.messagesFromHomeAction)
}
}
/*
* Personalized changes
*/
val changesTitle = view.findViewById<TextView>(R.id.changesTitleTextView)
val changesLayout = view.findViewById<LinearLayout>(R.id.changesLayout)
changesRecycler = view.findViewById(R.id.changesRecycler)
if (FunctionTilesDb.getInstance().supports(FunctionTile.FEATURE_CHANGES)) {
// Get changes for favorite courses and display them
val personalizedChanges = ChangesDb.instance!!.getFavorites()
// Create changes adapter
changesAdapter = CompactChangesAdapter(personalizedChanges) {
requireActivity().findNavController(R.id.nav_host_fragment)
.navigate(R.id.changesFromHomeAction, bundleOf("favorites" to personalizedChanges.isNotEmpty()))
}
changesRecycler.adapter = changesAdapter
changesRecycler.setHasFixedSize(true)
if (personalizedChanges.isEmpty()) {
changesTitle.text = getString(R.string.changes_personalized_none)
changesRecycler.visibility = View.GONE
}
// Set onclick if there are any changes, else display message
if (personalizedChanges.isNotEmpty() || ChangesDb.instance!!.existAny()) {
changesLayout.setOnClickListener {
requireActivity().findNavController(R.id.nav_host_fragment)
.navigate(R.id.changesFromHomeAction, bundleOf("favorites" to personalizedChanges.isNotEmpty()))
}
} else {
// Hide next icon if there are no changes
changesTitle.text = getString(R.string.changes_none)
changesTitle.setCompoundDrawablesRelative(null, null, null, null)
}
} else changesLayout.visibility = View.GONE
/**
* Undone tasks
*/
val tasksLayout = view.findViewById<LinearLayout>(R.id.tasksLayout)
tasksRecyclerLayout = view.findViewById(R.id.tasksRecyclerLayout)
tasksRecycler = view.findViewById(R.id.tasksRecycler)
tasksTitle = view.findViewById(R.id.tasksTitleTextView)
val moreTasksText = view.findViewById<TextView>(R.id.moreTasksTextView)
if (FunctionTilesDb.getInstance().supports(FunctionTile.FEATURE_COURSES)) {
tasks = TasksDb.getInstance().getUndoneData(false)
var tasksOverflow = 0
if (tasks.size > 6) {
tasksOverflow = tasks.size - 6
// Display more tasks message
moreTasksText.text = resources.getQuantityString(R.plurals.tasks_personalized_more, tasksOverflow, tasksOverflow)
moreTasksText.visibility = View.VISIBLE
}
if (tasks.isNotEmpty()) {
// Set up recycler with undone tasks, shows only 5 at a time
tasksRecycler.adapter = CompactTasksAdapter(
tasks,
6,
onClick = {
// Show single task bottom sheet
TaskSheet(it.id).show(parentFragmentManager, "task")
},
onTaskCheckedChanged = Tasks().onCheckedChanged(requireActivity()) { task, isDone ->
if (isDone) {
// Update tasks dataset
val index = tasks.indexOfFirst { it.id == task.id }
tasks.removeAt(index)
tasksRecycler.adapter?.notifyItemRemoved(index)
if (tasks.size < 6) (tasksRecycler.adapter as CompactTasksAdapter)
// Update overflow counter
if (tasksOverflow > 0) {
tasksOverflow--
if (tasksOverflow > 0)
moreTasksText.text = resources.getQuantityString(R.plurals.tasks_personalized_more, tasksOverflow, tasksOverflow)
else moreTasksText.visibility = View.GONE
}
// Update title and hide if necessary
updateTasksTitle()
}
}
)
}
// Show the number of undone tasks or that everything is done
// Will also handle hiding tasks recycler layout if necessary
updateTasksTitle()
// Open all undone tasks on click
tasksLayout.setOnClickListener {
Navigation.findNavController(requireActivity(), R.id.nav_host_fragment)
.navigate(R.id.tasksFromHomeAction, bundleOf("undone" to true))
}
} else tasksLayout.visibility = View.GONE
/*
* Unread posts
*/
val unreadPostsLayout = view.findViewById<LinearLayout>(R.id.unreadPostsLayout)
unreadPostsRecycler = view.findViewById(R.id.unreadPostsRecycler)
val moreUnreadText = view.findViewById<TextView>(R.id.moreUnreadTextView)
if (FunctionTilesDb.getInstance().supports(FunctionTile.FEATURE_COURSES)) {
// Get unread posts
// and up to 4 read posts
// We'll only display 4 posts,
// but unread posts will get removed once they are read
posts = PostsDb.getInstance().getData("posts.unread = 1")
var postsOverflow = 0
if (posts.size > 4) {
postsOverflow = posts.size - 4
// Display more unread posts text
moreUnreadText.text = resources.getQuantityString(R.plurals.posts_more_unread, postsOverflow, postsOverflow)
moreUnreadText.visibility = View.VISIBLE
}
posts.addAll(PostsDb.getInstance().getData("posts.unread = 0",
"ORDER BY posts.date DESC LIMIT 4"))
if (posts.isNotEmpty()) {
// Only show posts if there are any
unreadPostsRecycler.setHasFixedSize(true)
unreadPostsRecycler.adapter = CompactPostsAdapter(posts, 4)
{ post: CompactPostsAdapter.PostData, _: View ->
// Show single post bottom sheet
PostSheet(post.id).show(parentFragmentManager, "post")
// If the post was unread, mark as read
if (post.unread) {
PostsDb.getInstance().markAsRead(post.id)
post.unread = false
// Update overflow counter
postsOverflow--
if (postsOverflow != 0)
moreUnreadText.text = resources.getQuantityString(R.plurals.posts_more_unread, postsOverflow, postsOverflow)
else moreUnreadText.visibility = View.GONE
// Move the post down the list until it's at its correct position by date
val index = posts.indexOf(post)
var nextIndex = index
var postMoved = false
// Skip all indizes with posts that are also unread
// Maximum 8 shifts to avoid long runtime
while (nextIndex < 8
&& posts.getOrNull(nextIndex + 1) != null
&& (posts[nextIndex + 1].unread
|| post.date.before(posts[nextIndex + 1].date))) {
postMoved = true
// Overwrite this with the next post and notify the adapter
posts[nextIndex] = posts[nextIndex + 1]
unreadPostsRecycler.adapter?.notifyItemMoved(nextIndex + 1, nextIndex)
nextIndex++
}
// If the post moved, the entry at nextindex is now duplicated
// and can be replaced by this post, again update adapter for this position
if (postMoved) posts[nextIndex] = post
unreadPostsRecycler.adapter?.notifyItemChanged(nextIndex)
}
}
} else {
unreadPostsLayout.visibility = View.GONE
}
// Open all posts on click
unreadPostsLayout.setOnClickListener {
val bundle =
if (postsOverflow != 0) bundleOf("filters" to arrayOf("unread"))
else bundleOf()
Navigation.findNavController(requireActivity(), R.id.nav_host_fragment)
.navigate(R.id.allPostsFromHomeAction, bundle)
}
} else unreadPostsLayout.visibility = View.GONE
/**
* Pinned attachments
*/
val pinsLayout = view.findViewById<LinearLayout>(R.id.pinsLayout)
val pinsTitle = view.findViewById<TextView>(R.id.pinsTitleTextView)
val pinsRecycler = view.findViewById<RecyclerView>(R.id.pinsRecycler)
if (FunctionTilesDb.getInstance().supports(FunctionTile.FEATURE_COURSES)) {
val pins = AttachmentsDb.pins()
if (pins.isEmpty()) {
pinsTitle.text = getString(R.string.attachments_pins_none)
pinsRecycler.visibility = View.GONE
} else {
// Set up pins recycler
pinsRecycler.adapter = AttachmentsAdapter(
pins,
AttachmentManager().onAttachmentClick(requireActivity()) { _: Int, _: Attachment -> },
AttachmentManager().onAttachmentLongClick(requireActivity()) { action: Int, attachment: Attachment ->
if (action == AttachmentManager.ATTACHMENT_UNPINNED) {
// Attachment no longer pinned
// Remove it from the list
val index = pins.indexOf(attachment)
pins.removeAt(index)
// Notify the adapter
pinsRecycler.adapter?.notifyItemRemoved(index)
// Hide title and recycler if this was the last pin
if (pins.isEmpty()) {
pinsTitle.text = getString(R.string.attachments_pins_none)
pinsRecycler.visibility = View.GONE
}
} else if (action == AttachmentManager.ATTACHMENT_RENAMED_PIN) {
// Update item in recycler
val index = pins.indexOfFirst { it.attachId() == attachment.attachId() }
pins[index] = attachment
pinsRecycler.adapter?.notifyItemChanged(index)
}
},
true
)
PagerSnapHelper().attachToRecyclerView(pinsRecycler)
}
// Open all attachments fragment on click
pinsLayout.setOnClickListener {
requireActivity().findNavController(R.id.nav_host_fragment)
.navigate(R.id.frag_placeholder)
// todo attachments collection
}
} else pinsLayout.visibility = View.GONE
return view
}
override fun onDestroy() {
// Unregister broadcast receiver
LocalBroadcastManager.getInstance(requireActivity()).unregisterReceiver(uichangeReceiver)
super.onDestroy()
}
}
No newline at end of file
ndex ea0b138..67794b7 100644
++ b/app/src/main/java/de/koenidv/sph/ui/OnboardingSigninFragment.kt
39e63d8ffe07d4442fb7e9e3426ae2da8be5a994
github-actions commented
Closed in 835d111