This commit is contained in:
Erik Cavazos 2023-07-08 17:11:55 -06:00
parent 86dc367837
commit e88f5676ac
25 changed files with 365 additions and 168 deletions

View File

@ -18,7 +18,7 @@
<PersistentState> <PersistentState>
<option name="values"> <option name="values">
<map> <map>
<entry key="url" value="file:/$USER_HOME$/AppData/Local/Android/Sdk/icons/material/materialicons/report/baseline_report_24.xml" /> <entry key="url" value="file:/$USER_HOME$/AppData/Local/Android/Sdk/icons/material/materialicons/search/baseline_search_24.xml" />
</map> </map>
</option> </option>
</PersistentState> </PersistentState>
@ -28,7 +28,7 @@
</option> </option>
<option name="values"> <option name="values">
<map> <map>
<entry key="outputName" value="baseline_report_24" /> <entry key="outputName" value="baseline_search_24" />
<entry key="sourceFile" value="C:\Users\erike\Downloads\comments-solid.svg" /> <entry key="sourceFile" value="C:\Users\erike\Downloads\comments-solid.svg" />
</map> </map>
</option> </option>

View File

@ -41,13 +41,13 @@ android {
dependencies { dependencies {
implementation 'androidx.core:core-ktx:1.10.1' implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.appcompat:appcompat:1.6.0' implementation 'androidx.appcompat:appcompat:1.6.1'
implementation "androidx.recyclerview:recyclerview:1.3.0" implementation "androidx.recyclerview:recyclerview:1.3.0"
implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1' implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1'
implementation 'com.google.code.gson:gson:2.10.1' implementation 'com.google.code.gson:gson:2.10.1'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0' implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
@ -64,7 +64,7 @@ dependencies {
// Material 3 // Material 3
implementation "com.google.android.material:material:1.8.0" implementation "com.google.android.material:material:1.9.0"
// Navigation // Navigation
def nav_version = "2.6.0" def nav_version = "2.6.0"
@ -74,7 +74,7 @@ dependencies {
androidTestImplementation "androidx.navigation:navigation-testing:$nav_version" androidTestImplementation "androidx.navigation:navigation-testing:$nav_version"
// Splash screen // Splash screen
implementation "androidx.core:core-splashscreen:1.0.0" implementation "androidx.core:core-splashscreen:1.0.1"
// Data security // Data security
implementation "androidx.security:security-crypto:1.0.0" implementation "androidx.security:security-crypto:1.0.0"

View File

@ -22,7 +22,7 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name=".home.HomeActivity" android:theme="@style/Theme.Isolaatti" /> <activity android:name=".home.HomeActivity" android:theme="@style/Theme.Isolaatti" android:windowSoftInputMode="adjustResize" />
<activity android:name=".login.LogInActivity" android:theme="@style/Theme.Isolaatti" /> <activity android:name=".login.LogInActivity" android:theme="@style/Theme.Isolaatti" />
<activity android:name=".profile.ui.ProfileActivity" android:theme="@style/Theme.Isolaatti"/> <activity android:name=".profile.ui.ProfileActivity" android:theme="@style/Theme.Isolaatti"/>
<activity android:name=".settings.ui.SettingsActivity" android:theme="@style/Theme.Isolaatti"/> <activity android:name=".settings.ui.SettingsActivity" android:theme="@style/Theme.Isolaatti"/>

View File

@ -21,7 +21,8 @@ class HomeActivity : AppCompatActivity() {
viewBinding = ActivityHomeBinding.inflate(layoutInflater) viewBinding = ActivityHomeBinding.inflate(layoutInflater)
setContentView(viewBinding.root) setContentView(viewBinding.root)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
viewBinding.bottomNavigation.setupWithNavController(navHostFragment.navController) viewBinding.bottomNavigation?.setupWithNavController(navHostFragment.navController)
viewBinding.navigationRail?.setupWithNavController(navHostFragment.navController)
if(savedInstanceState == null) { if(savedInstanceState == null) {
postsViewModel.getFeed() postsViewModel.getFeed()

View File

@ -4,12 +4,20 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.dialog.MaterialDialogs
import com.isolaatti.R
import com.isolaatti.databinding.BottomSheetPostCommentsBinding import com.isolaatti.databinding.BottomSheetPostCommentsBinding
import com.isolaatti.posting.common.domain.OnUserInteractedCallback import com.isolaatti.posting.common.domain.OnUserInteractedCallback
import com.isolaatti.posting.common.options_bottom_sheet.domain.OptionClicked
import com.isolaatti.posting.common.options_bottom_sheet.domain.Options import com.isolaatti.posting.common.options_bottom_sheet.domain.Options
import com.isolaatti.posting.common.options_bottom_sheet.presentation.BottomSheetPostOptionsViewModel import com.isolaatti.posting.common.options_bottom_sheet.presentation.BottomSheetPostOptionsViewModel
import com.isolaatti.posting.common.options_bottom_sheet.ui.BottomSheetPostOptionsFragment import com.isolaatti.posting.common.options_bottom_sheet.ui.BottomSheetPostOptionsFragment
@ -23,11 +31,20 @@ import io.noties.markwon.linkify.LinkifyPlugin
@AndroidEntryPoint @AndroidEntryPoint
class BottomSheetPostComments() : BottomSheetDialogFragment(), OnUserInteractedCallback { class BottomSheetPostComments() : BottomSheetDialogFragment(), OnUserInteractedCallback {
private lateinit var viewBinding: BottomSheetPostCommentsBinding private lateinit var viewBinding: BottomSheetPostCommentsBinding
val viewModel: CommentsViewModel by viewModels() val viewModel: CommentsViewModel by viewModels()
val optionsViewModel: BottomSheetPostOptionsViewModel by activityViewModels() val optionsViewModel: BottomSheetPostOptionsViewModel by activityViewModels()
val optionsObserver: Observer<OptionClicked> = Observer {
if(it.callerId == CALLER_ID) {
optionsViewModel.optionClicked(-1)
}
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val postId = arguments?.getLong(ARG_POST_ID) val postId = arguments?.getLong(ARG_POST_ID)
@ -43,6 +60,7 @@ class BottomSheetPostComments() : BottomSheetDialogFragment(), OnUserInteractedC
): View { ): View {
viewBinding = BottomSheetPostCommentsBinding.inflate(inflater) viewBinding = BottomSheetPostCommentsBinding.inflate(inflater)
(dialog as BottomSheetDialog).behavior.state = BottomSheetBehavior.STATE_EXPANDED
return viewBinding.root return viewBinding.root
} }
@ -71,12 +89,24 @@ class BottomSheetPostComments() : BottomSheetDialogFragment(), OnUserInteractedC
viewModel.comments.observe(viewLifecycleOwner) { viewModel.comments.observe(viewLifecycleOwner) {
adapter.submitList(it) adapter.submitList(it)
} }
// New comment area
val textField = viewBinding.newCommentTextField
textField.setStartIconOnClickListener {
AlertDialog.Builder(requireContext()).setView(R.layout.write_comment_multiline_dialog).show()
}
optionsViewModel.optionClicked(-1)
optionsViewModel.optionClicked.observe(viewLifecycleOwner, optionsObserver)
} }
companion object { companion object {
const val TAG = "BottomSheetPostComments" const val TAG = "BottomSheetPostComments"
const val ARG_POST_ID = "postId" const val ARG_POST_ID = "postId"
const val CALLER_ID = 10
fun getInstance(postId: Long): BottomSheetPostComments { fun getInstance(postId: Long): BottomSheetPostComments {
return BottomSheetPostComments().apply { return BottomSheetPostComments().apply {
@ -89,9 +119,9 @@ class BottomSheetPostComments() : BottomSheetDialogFragment(), OnUserInteractedC
override fun onOptions(postId: Long) { override fun onOptions(postId: Long) {
optionsViewModel.setOptions(Options.commentOptions, CALLER_ID)
val fragment = BottomSheetPostOptionsFragment() val fragment = BottomSheetPostOptionsFragment()
fragment.show(parentFragmentManager, BottomSheetPostOptionsFragment.TAG) fragment.show(parentFragmentManager, BottomSheetPostOptionsFragment.TAG)
optionsViewModel.setOptions(Options.commentOptions)
} }
override fun onProfileClick(userId: Int) { override fun onProfileClick(userId: Int) {

View File

@ -0,0 +1,3 @@
package com.isolaatti.posting.common.options_bottom_sheet.domain
data class OptionClicked(val optionId: Int, val callerId: Int)

View File

@ -10,20 +10,27 @@ data class Options(
) { ) {
data class Option( data class Option(
@StringRes val stringRes: Int, @StringRes val stringRes: Int,
@DrawableRes val icon: Int @DrawableRes val icon: Int,
) val optionId: Int
) {
companion object {
const val OPTION_DELETE = 1
const val OPTION_EDIT = 2
const val OPTION_REPORT = 3
}
}
companion object { companion object {
val postOptions = Options(R.string.post_options_title, listOf( val postOptions = Options(R.string.post_options_title, listOf(
Option(R.string.delete, R.drawable.baseline_delete_24), Option(R.string.delete, R.drawable.baseline_delete_24, Option.OPTION_DELETE),
Option(R.string.edit, R.drawable.baseline_edit_24), Option(R.string.edit, R.drawable.baseline_edit_24, Option.OPTION_EDIT),
Option(R.string.report, R.drawable.baseline_report_24) Option(R.string.report, R.drawable.baseline_report_24, Option.OPTION_REPORT)
)) ))
val commentOptions = Options(R.string.post_options_title, listOf( val commentOptions = Options(R.string.post_options_title, listOf(
Option(R.string.delete, R.drawable.baseline_delete_24), Option(R.string.delete, R.drawable.baseline_delete_24, Option.OPTION_DELETE),
Option(R.string.edit, R.drawable.baseline_edit_24), Option(R.string.edit, R.drawable.baseline_edit_24, Option.OPTION_EDIT),
Option(R.string.report, R.drawable.baseline_report_24) Option(R.string.report, R.drawable.baseline_report_24, Option.OPTION_REPORT)
)) ))
} }
} }

View File

@ -3,13 +3,25 @@ package com.isolaatti.posting.common.options_bottom_sheet.presentation
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import com.isolaatti.posting.common.options_bottom_sheet.domain.OptionClicked
import com.isolaatti.posting.common.options_bottom_sheet.domain.Options import com.isolaatti.posting.common.options_bottom_sheet.domain.Options
class BottomSheetPostOptionsViewModel : ViewModel() { class BottomSheetPostOptionsViewModel : ViewModel() {
private val _options: MutableLiveData<Options> = MutableLiveData() private val _options: MutableLiveData<Options> = MutableLiveData()
val options: LiveData<Options> get() = _options val options: LiveData<Options> get() = _options
fun setOptions(options: Options) { private var _callerId: Int = 0
private val _optionClicked: MutableLiveData<OptionClicked> = MutableLiveData()
val optionClicked: LiveData<OptionClicked> get() = _optionClicked
fun setOptions(options: Options, callerId: Int) {
_options.postValue(options) _options.postValue(options)
_callerId = callerId
} }
fun optionClicked(optionId: Int) {
_optionClicked.postValue(OptionClicked(optionId, _callerId))
}
} }

View File

@ -0,0 +1,41 @@
package com.isolaatti.posting.common.options_bottom_sheet.presentation
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.appcompat.content.res.AppCompatResources
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.RecyclerView
import com.isolaatti.databinding.OptionItemBinding
import com.isolaatti.posting.common.options_bottom_sheet.domain.Options
class OptionsRecyclerAdapter(val options: List<Options.Option>, private val optionCallback: OptionsCallback) : RecyclerView.Adapter<OptionsRecyclerAdapter.OptionViewHolder>() {
inner class OptionViewHolder(val viewBinding: OptionItemBinding) : RecyclerView.ViewHolder(viewBinding.root)
fun interface OptionsCallback {
fun optionClicked(optionId: Int)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OptionViewHolder {
return OptionViewHolder(
OptionItemBinding.inflate(LayoutInflater.from(parent.context)).apply {
root.layoutParams = ConstraintLayout.LayoutParams(
ConstraintLayout.LayoutParams.MATCH_PARENT,
ConstraintLayout.LayoutParams.WRAP_CONTENT
)
}
)
}
override fun getItemCount(): Int = options.count()
override fun onBindViewHolder(holder: OptionViewHolder, position: Int) {
holder.viewBinding.optionButton.apply {
text = context.getText(options[position].stringRes)
icon = AppCompatResources.getDrawable(context, options[position].icon)
setOnClickListener {
optionCallback.optionClicked(options[position].optionId)
}
}
}
}

View File

@ -8,14 +8,17 @@ import android.widget.ListAdapter
import android.widget.ListView import android.widget.ListView
import androidx.appcompat.content.res.AppCompatResources import androidx.appcompat.content.res.AppCompatResources
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import com.isolaatti.R import com.isolaatti.R
import com.isolaatti.databinding.BottomSheetPostOptionsBinding import com.isolaatti.databinding.BottomSheetPostOptionsBinding
import com.isolaatti.posting.common.options_bottom_sheet.domain.Options import com.isolaatti.posting.common.options_bottom_sheet.domain.Options
import com.isolaatti.posting.common.options_bottom_sheet.presentation.BottomSheetPostOptionsViewModel import com.isolaatti.posting.common.options_bottom_sheet.presentation.BottomSheetPostOptionsViewModel
import com.isolaatti.posting.common.options_bottom_sheet.presentation.OptionsRecyclerAdapter
class BottomSheetPostOptionsFragment : BottomSheetDialogFragment() { class BottomSheetPostOptionsFragment : BottomSheetDialogFragment(), OptionsRecyclerAdapter.OptionsCallback {
private lateinit var viewBinding: BottomSheetPostOptionsBinding private lateinit var viewBinding: BottomSheetPostOptionsBinding
private val viewModel: BottomSheetPostOptionsViewModel by activityViewModels() private val viewModel: BottomSheetPostOptionsViewModel by activityViewModels()
@ -28,27 +31,29 @@ class BottomSheetPostOptionsFragment : BottomSheetDialogFragment() {
): View { ): View {
viewBinding = BottomSheetPostOptionsBinding.inflate(inflater) viewBinding = BottomSheetPostOptionsBinding.inflate(inflater)
return viewBinding.root return viewBinding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
viewModel.options.observe(viewLifecycleOwner) { viewModel.options.observe(viewLifecycleOwner) {
renderOptions(it) renderOptions(it)
} }
viewModel.optionClicked.observe(viewLifecycleOwner) {
if(it.optionId > -1) {
(dialog as BottomSheetDialog).dismiss()
}
}
} }
private fun renderOptions(options: Options) { private fun renderOptions(options: Options) {
viewBinding.optionsContainer.removeAllViews() viewBinding.recyclerOptions.adapter = OptionsRecyclerAdapter(options.items, this)
for(option in options.items) { viewBinding.recyclerOptions.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
val button = MaterialButton(requireContext(), null, com.google.android.material.R.style.Widget_Material3_Button_TextButton)
button.icon = AppCompatResources.getDrawable(requireContext(), option.icon)
button.text = requireContext().getText(option.stringRes)
button.textAlignment = MaterialButton.TEXT_ALIGNMENT_TEXT_START
viewBinding.optionsContainer.addView(button)
}
} }
companion object { companion object {
@ -56,4 +61,8 @@ class BottomSheetPostOptionsFragment : BottomSheetDialogFragment() {
} }
override fun optionClicked(optionId: Int) {
viewModel.optionClicked(optionId)
}
} }

View File

@ -34,11 +34,11 @@ class PostsRecyclerViewAdapter (private val markwon: Markwon, private val callba
likeButton.isEnabled = true likeButton.isEnabled = true
if(postDto.liked) { if(postDto.liked) {
likeButton.setIconTintResource(R.color.purple_700) likeButton.setIconTintResource(R.color.purple_lighter)
likeButton.setTextColor(itemView.context.getColor(R.color.purple_700)) likeButton.setTextColor(itemView.context.getColor(R.color.purple_lighter))
} else { } else {
likeButton.setIconTintResource(R.color.black) likeButton.setIconTintResource(R.color.on_surface)
likeButton.setTextColor(itemView.context.getColor(R.color.black)) likeButton.setTextColor(itemView.context.getColor(R.color.on_surface))
} }
likeButton.text = postDto.numberOfLikes.toString() likeButton.text = postDto.numberOfLikes.toString()
@ -70,11 +70,11 @@ class PostsRecyclerViewAdapter (private val markwon: Markwon, private val callba
likeButton.isEnabled = true likeButton.isEnabled = true
if(postDto.liked) { if(postDto.liked) {
likeButton.setIconTintResource(R.color.purple_700) likeButton.setIconTintResource(R.color.purple_lighter)
likeButton.setTextColor(itemView.context.getColor(R.color.purple_700)) likeButton.setTextColor(itemView.context.getColor(R.color.purple_lighter))
} else { } else {
likeButton.setIconTintResource(R.color.black) likeButton.setIconTintResource(R.color.on_surface)
likeButton.setTextColor(itemView.context.getColor(R.color.black)) likeButton.setTextColor(itemView.context.getColor(R.color.on_surface))
} }
likeButton.text = postDto.numberOfLikes.toString() likeButton.text = postDto.numberOfLikes.toString()

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
</vector>

View File

@ -0,0 +1,30 @@
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.navigationrail.NavigationRailView
android:id="@+id/navigation_rail"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:menu="@menu/home_menu" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/navigation_rail"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/home_navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,13 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout <FrameLayout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_container" android:id="@+id/main_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"> xmlns:android="http://schemas.android.com/apk/res/android">
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
@ -20,63 +19,55 @@
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:context=".feed.ui.FeedFragment"> tools:context=".feed.ui.FeedFragment">
<com.google.android.material.search.SearchBar
android:id="@+id/search_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:hint="@string/searchbar_hint" />
<com.google.android.material.search.SearchView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="@string/searchbar_hint"
app:layout_anchor="@id/search_bar">
<!-- Search suggestions/results go here (ScrollView, RecyclerView, etc.). -->
</com.google.android.material.search.SearchView>
<FrameLayout <FrameLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent">
android:layout_marginBottom="80dp">
<LinearLayout <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical"
android:id="@+id/linearLayout">
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:id="@+id/topAppBar_layout" android:id="@+id/topAppBar_layout"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:layout_conversion_absoluteHeight="64dp"
tools:layout_conversion_absoluteWidth="531dp">
<com.google.android.material.appbar.MaterialToolbar <com.google.android.material.appbar.MaterialToolbar
android:id="@+id/topAppBar" android:id="@+id/topAppBar"
style="@style/Theme.Isolaatti" style="@style/Theme.Isolaatti"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="match_parent"
app:navigationIcon="@drawable/baseline_menu_24"
app:title="@string/app_name" app:title="@string/app_name"
app:titleCentered="true" /> app:titleCentered="true"
tools:layout_conversion_absoluteHeight="64dp"
tools:layout_conversion_absoluteWidth="531dp"
tools:layout_editor_absoluteX="360dp"
tools:layout_editor_absoluteY="0dp" />
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/feed_recycler_view" android:id="@+id/feed_recycler_view"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="match_parent" /> android:layout_height="0dp"
</LinearLayout> app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/topAppBar_layout"
tools:layout_conversion_absoluteHeight="242dp"
tools:layout_conversion_absoluteWidth="531dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/floating_action_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:contentDescription=""
app:srcCompat="@drawable/baseline_add_24" />
</FrameLayout> </FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -30,41 +30,61 @@
android:id="@+id/recycler_comments" android:id="@+id/recycler_comments"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="400dp" android:layout_height="400dp"
app:layout_constraintBottom_toTopOf="@id/newCommentTextField" app:layout_constraintBottom_toTopOf="@id/new_comment_area"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/topAppBar_layout" /> app:layout_constraintTop_toBottomOf="@id/topAppBar_layout" />
<androidx.constraintlayout.widget.ConstraintLayout
<com.google.android.material.textfield.TextInputLayout android:id="@+id/new_comment_area"
android:id="@+id/newCommentTextField" android:layout_width="match_parent"
style="?attr/textInputOutlinedStyle"
android:layout_margin="8dp"
app:boxCornerRadiusBottomEnd="20dp"
app:boxCornerRadiusBottomStart="20dp"
app:boxCornerRadiusTopEnd="20dp"
app:boxCornerRadiusTopStart="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/submitCommentButton"
app:layout_constraintStart_toStartOf="parent"
android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hint="@string/new_comment">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/submitCommentButton"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_margin="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/newCommentTextField"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:icon="@drawable/baseline_send_24"/> app:layout_constraintStart_toStartOf="parent">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/newCommentTextField"
style="?attr/textInputOutlinedStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:layout_marginStart="4dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="4dp"
android:layout_marginBottom="4dp"
android:hint="@string/new_comment"
app:boxCornerRadiusBottomEnd="20dp"
app:boxCornerRadiusBottomStart="20dp"
app:boxCornerRadiusTopEnd="20dp"
app:boxCornerRadiusTopStart="20dp"
app:startIconDrawable="@drawable/baseline_open_in_full_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/submitCommentButton"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/submitCommentButton"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_margin="8dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="4dp"
android:layout_marginBottom="4dp"
app:icon="@drawable/baseline_send_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -9,32 +9,8 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"/>
<LinearLayout <androidx.recyclerview.widget.RecyclerView
android:id="@+id/options_container" android:id="@+id/recycler_options"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"/>
android:orientation="vertical">
<com.google.android.material.button.MaterialButton
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/edit"
android:textAlignment="textStart" />
<com.google.android.material.button.MaterialButton
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/delete"
android:textAlignment="textStart" />
<com.google.android.material.button.MaterialButton
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/report"
android:textAlignment="textStart" />
</LinearLayout>
</LinearLayout> </LinearLayout>

View File

@ -1,12 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout <FrameLayout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_container" android:id="@+id/main_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"> xmlns:android="http://schemas.android.com/apk/res/android">
<androidx.drawerlayout.widget.DrawerLayout <androidx.drawerlayout.widget.DrawerLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout" android:id="@+id/drawer_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
@ -16,31 +15,17 @@
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".feed.ui.FeedFragment"> tools:context=".feed.ui.FeedFragment">
<com.google.android.material.search.SearchBar
android:id="@+id/search_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:hint="@string/searchbar_hint" />
<com.google.android.material.search.SearchView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="@string/searchbar_hint"
app:layout_anchor="@id/search_bar">
<!-- Search suggestions/results go here (ScrollView, RecyclerView, etc.). -->
</com.google.android.material.search.SearchView>
<FrameLayout <FrameLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginBottom="80dp"> android:layout_marginBottom="0dp">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:id="@+id/topAppBar_layout" android:id="@+id/topAppBar_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -50,14 +35,15 @@
android:id="@+id/topAppBar" android:id="@+id/topAppBar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
app:titleCentered="true" android:theme="@style/Theme.Isolaatti"
style="@style/Theme.Isolaatti"
app:navigationIcon="@drawable/baseline_menu_24" app:navigationIcon="@drawable/baseline_menu_24"
app:title="@string/app_name"/> app:navigationIconTint="@color/on_surface"
app:title="@string/app_name"
app:titleCentered="true" />
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/feed_recycler_view" android:id="@+id/feed_recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/option_container"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.button.MaterialButton
android:id="@+id/option_button"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
android:textAlignment="textStart"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Options" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,40 @@
<?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"
style="@style/Widget.MaterialComponents.CardView"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/commentEditTextTextMultiLine"
style="@style/Widget.Material3.TextInputLayout.FilledBox.Dense"
android:layout_width="0dp"
android:layout_height="500dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:ems="10"
android:gravity="start|top"
android:inputType="textMultiLine"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/close_button">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxHeight="500dp" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/close_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:text="@string/close"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -4,9 +4,13 @@
<item <item
android:id="@+id/feedFragment" android:id="@+id/feedFragment"
android:icon="@drawable/baseline_home_24" android:icon="@drawable/baseline_home_24"
android:title="Feed" /> android:title="@string/home" />
<item <item
android:id="@+id/notificationsFragment" android:id="@+id/notificationsFragment"
android:icon="@drawable/baseline_notifications_24" android:icon="@drawable/baseline_notifications_24"
android:title="Notifications" /> android:title="@string/notifications" />
<item
android:id="@+id/searchFragment"
android:icon="@drawable/baseline_search_24"
android:title="@string/search" />
</menu> </menu>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple">#4d3b68</color>
<color name="purple_lighter">#7015ea</color>
<color name="surface">#1D1725</color>
<color name="on_surface">#FFFFFF</color>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Isolaatti" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Primary brand color. -->
<item name="android:colorPrimary">@color/purple</item>
<item name="android:statusBarColor">@color/purple</item>
<item name="colorOnSurface">@color/on_surface</item>
</style>
</resources>

View File

@ -1,10 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="purple_200">#FFBB86FC</color> <color name="purple">#4d3b68</color>
<color name="purple_500">#FF6200EE</color> <color name="purple_lighter">#7015ea</color>
<color name="purple_700">#FF3700B3</color> <color name="surface">@color/design_default_color_background</color>
<color name="teal_200">#FF03DAC5</color> <color name="on_surface">#000000</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources> </resources>

View File

@ -16,7 +16,11 @@
<string name="delete">Delete</string> <string name="delete">Delete</string>
<string name="new_comment">New comment</string> <string name="new_comment">New comment</string>
<string name="report">Report</string> <string name="report">Report</string>
<string name="close">Close</string>
<!--Post options --> <!--Post options -->
<string name="post_options_title">Discussion options</string> <string name="post_options_title">Discussion options</string>
<string name="home">Home</string>
<string name="notifications">Notifications</string>
<string name="search">Search</string>
</resources> </resources>

View File

@ -1,10 +1,10 @@
<resources xmlns:tools="http://schemas.android.com/tools"> <resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="Theme.Isolaatti" parent="Theme.Material3.DayNight.NoActionBar"> <style name="Theme.Isolaatti" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Primary brand color. --> <item name="android:colorPrimary">@color/purple</item>
<!-- Secondary brand color. --> <item name="colorSurface">@color/surface</item>
<!-- Status bar color. --> <item name="colorOnSurface">@color/on_surface</item>
<!-- Customize your theme here. --> <item name="android:statusBarColor">@color/purple</item>
</style> </style>
<style name="Theme.Isolaatti.Splash" parent="Theme.SplashScreen"/> <style name="Theme.Isolaatti.Splash" parent="Theme.SplashScreen"/>