Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GC-56 implement course menu #38

Merged
merged 2 commits into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions front_end/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".course.ui.activtiy.CourseActivity"
android:exported="true"
android:theme="@style/Theme.MyApplication">
</activity>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.example.studentportal.course.ui.activtiy

import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.MenuItem
import androidx.annotation.VisibleForTesting
import androidx.fragment.app.FragmentActivity
import com.example.studentportal.R
import com.example.studentportal.common.ui.showFragment
import com.example.studentportal.course.ui.fragment.CourseFragment
import com.example.studentportal.course.ui.model.UserType
import com.example.studentportal.databinding.ActivityCourseBinding
import com.example.studentportal.home.ui.model.BaseCourseUiModel

class CourseActivity : FragmentActivity() {
@VisibleForTesting
internal lateinit var binding: ActivityCourseBinding

private val userType: UserType
get() {
val name = intent.getStringExtra(KEY_USER_TYPE)
return UserType.valueOf(name.orEmpty())
}

private val userId: String
get() {
return intent.getStringExtra(KEY_USER_ID).orEmpty()
}

private val courseId: String
get() {
return intent.getStringExtra(KEY_COURSE_ID).orEmpty()
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityCourseBinding.inflate(layoutInflater).initUi()
actionBar?.apply {
setHomeButtonEnabled(true)
setDisplayHomeAsUpEnabled(true)
setHomeAsUpIndicator(R.drawable.arrow_back)
}
supportFragmentManager.showFragment(
fragment = CourseFragment.newInstance(
userType = userType,
userId = userId,
courseId = courseId
),
addToBackStack = false,
containerId = binding.flContent.id
)
setContentView(binding.root)
}

private fun ActivityCourseBinding.initUi(): ActivityCourseBinding {
toolbar.setTitle(intent.getStringExtra(KEY_USER_COURSE_NAME))
setActionBar(this.toolbar)
return this
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
onBackPressedDispatcher.onBackPressed()
return super.onOptionsItemSelected(item)
}

companion object {
const val KEY_USER_ID = "KEY_USER_ID"
const val KEY_USER_TYPE = "KEY_USER_TYPE"
const val KEY_COURSE_ID = "KEY_COURSE_ID"
const val KEY_USER_COURSE_NAME = "KEY_COURSE_NAME"
fun intent(
owner: Context,
course: BaseCourseUiModel.CourseUiModel,
userId: String,
userType: String
): Intent {
val intent = Intent(owner, CourseActivity::class.java)
intent.putExtra(KEY_USER_ID, userId)
intent.putExtra(KEY_USER_TYPE, userType)
intent.putExtra(KEY_COURSE_ID, course.id)
intent.putExtra(KEY_USER_COURSE_NAME, course.name)
return intent
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.example.studentportal.course.ui.fragment

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.os.bundleOf
import com.example.studentportal.common.ui.fragment.BaseFragment
import com.example.studentportal.course.ui.layout.CourseMenuLayout
import com.example.studentportal.course.ui.model.Command
import com.example.studentportal.course.ui.model.UserType
import com.example.studentportal.databinding.FragmentCourseBinding

class CourseFragment : BaseFragment<FragmentCourseBinding>(TAG) {

private val userType: UserType
get() {
val name = requireArguments().getString(KEY_USER_TYPE)
return UserType.valueOf(name = name.orEmpty())
}

override fun inflateBinding(
inflater: LayoutInflater,
container: ViewGroup?
): FragmentCourseBinding {
val binding = FragmentCourseBinding.inflate(inflater, container, false)
binding.composeView.setContent {
CourseMenuLayout(userType = userType) {
when (it) {
Command.ShowAssignments -> {
// TODO set up assignments
}
Command.ShowContent -> {
// TODO show course content
}
Command.ShowStudents -> {
// TODO show students
}
Command.Nothing -> Unit // Default
}
}
}
return binding
}

override fun menuItem(): Int = -1

companion object {
const val TAG = "COURSE"
const val KEY_USER_TYPE = "KEY_USER_TYPE"
const val KEY_USER_ID = "KEY_USER_ID"
const val KEY_COURSE_ID = "KEY_COURSE_ID"

fun newInstance(
userType: UserType,
userId: String,
courseId: String
): CourseFragment {
val fragment = CourseFragment()
fragment.arguments = bundleOf(
KEY_COURSE_ID to courseId,
KEY_USER_ID to userId,
KEY_USER_TYPE to userType.name
)
return fragment
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package com.example.studentportal.course.ui.layout

import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.KeyboardArrowRight
import androidx.compose.material3.Divider
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester.Companion.createRefs
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.constraintlayout.compose.ConstraintLayout
import com.example.studentportal.course.ui.model.Command
import com.example.studentportal.course.ui.model.CourseMenuItem
import com.example.studentportal.course.ui.model.UserType

@Composable
fun CourseMenuLayout(
userType: UserType,
modifier: Modifier = Modifier,
onClicked: (command: Command) -> Unit
) {
LazyColumn(modifier) {
items(userType.menuItems) {
MenuItem(
menuItem = it,
onClicked = onClicked
)
}
}
}

@Composable
fun MenuItem(
menuItem: CourseMenuItem,
onClicked: (command: Command) -> Unit,
modifier: Modifier = Modifier
) {
ConstraintLayout(
modifier = Modifier
.height(64.dp)
.fillMaxWidth()
.clickable {
onClicked.invoke(menuItem.command)
}
) {
val (icon, title, arrow, divider) = createRefs()
Icon(
modifier = modifier
.constrainAs(icon) {
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(parent.start, margin = 16.dp)
},
imageVector = menuItem.icon,
contentDescription = null
)
Text(
modifier = modifier
.wrapContentHeight()
.padding(start = 16.dp, end = 16.dp)
.constrainAs(title) {
top.linkTo(icon.top)
bottom.linkTo(icon.bottom)
start.linkTo(icon.end)
},
text = stringResource(id = menuItem.titleRes),
textAlign = TextAlign.Start,
style = TextStyle(fontSize = 22.sp)
)
Icon(
modifier = modifier
.constrainAs(arrow) {
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
end.linkTo(parent.end, margin = 16.dp)
},
imageVector = Icons.Outlined.KeyboardArrowRight,
contentDescription = null
)
Divider(
modifier = modifier
.constrainAs(divider) {
top.linkTo(parent.bottom, margin = 0.dp)
start.linkTo(parent.start, margin = 0.dp)
end.linkTo(parent.end, margin = 0.dp)
}
.wrapContentSize()
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.example.studentportal.course.ui.model

import androidx.annotation.StringRes
import androidx.compose.ui.graphics.vector.ImageVector

data class CourseMenuItem(
@StringRes val titleRes: Int,
val icon: ImageVector,
val command: Command
)

sealed interface Command {
object ShowStudents : Command
object ShowAssignments : Command
object ShowContent : Command
object Nothing : Command
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.example.studentportal.course.ui.model

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Create
import androidx.compose.material.icons.filled.Face
import androidx.compose.material.icons.filled.Info
import com.example.studentportal.R

enum class UserType(
val menuItems: List<CourseMenuItem>
) {
FACULTY(
menuItems = listOf(
CourseMenuItem(
titleRes = R.string.courses_menu_content,
icon = Icons.Default.Info,
command = Command.ShowContent
),
CourseMenuItem(
titleRes = R.string.courses_menu_students,
icon = Icons.Default.Face,
command = Command.ShowStudents
),
CourseMenuItem(
titleRes = R.string.courses_menu_assignments,
icon = Icons.Default.Create,
command = Command.ShowAssignments
)
)
),
STUDENT(
menuItems = listOf(
CourseMenuItem(
titleRes = R.string.courses_menu_content,
icon = Icons.Default.Info,
command = Command.ShowContent
),
CourseMenuItem(
titleRes = R.string.courses_menu_assignments,
icon = Icons.Default.Create,
command = Command.ShowAssignments
)
)
),
ADMIN(
menuItems = listOf(
CourseMenuItem(
titleRes = R.string.courses_menu_students,
icon = Icons.Default.Face,
command = Command.ShowStudents
)
)
),
UNKNOWN(listOf());

companion object {
fun valueOf(name: String): UserType {
return UserType.entries.firstOrNull { it.name == name } ?: UNKNOWN
}
}
}
Loading
Loading