WIP agregar foto

This commit is contained in:
Erik Everardo 2023-11-20 22:53:14 -06:00
parent 05962ff483
commit a07a323f1d
29 changed files with 347 additions and 48 deletions

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<targetSelectedWithDropDown>
<Target>
<type value="QUICK_BOOT_TARGET" />
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="$USER_HOME$/.android/avd/Pixel_3a_API_34_extension_level_7_x86_64.avd" />
</Key>
</deviceKey>
</Target>
</targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2023-11-19T23:31:08.478703551Z" />
</component>
</project>

View File

@ -36,6 +36,14 @@
<activity android:name=".about.AboutActivity" android:theme="@style/Theme.Isolaatti"/> <activity android:name=".about.AboutActivity" android:theme="@style/Theme.Isolaatti"/>
<activity android:name=".images.picture_viewer.ui.PictureViewerActivity" android:theme="@style/Theme.Isolaatti"/> <activity android:name=".images.picture_viewer.ui.PictureViewerActivity" android:theme="@style/Theme.Isolaatti"/>
<activity android:name=".sign_up.ui.SignUpActivity" android:theme="@style/Theme.Isolaatti"/> <activity android:name=".sign_up.ui.SignUpActivity" android:theme="@style/Theme.Isolaatti"/>
<provider
android:authorities="com.isolaatti.provider"
android:name="androidx.core.content.FileProvider"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
</application> </application>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
</manifest> </manifest>

View File

@ -0,0 +1,7 @@
package com.isolaatti
import androidx.core.content.FileProvider
class MyFileProvider : FileProvider() {
}

View File

@ -197,7 +197,7 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
image?.load(UrlGen.userProfileImage(it.userId), imageLoader) image?.load(UrlGen.userProfileImage(it.userId), imageLoader)
image?.setOnClickListener {_ -> image?.setOnClickListener {_ ->
PictureViewerActivity.startActivityWithUrls(requireContext(), arrayOf(UrlGen.userProfileImageFullQuality(it.userId))) //PictureViewerActivity.startActivityWithImages(requireContext(), arrayOf(UrlGen.userProfileImageFullQuality(it.userId)))
} }
textViewName?.text = it.name textViewName?.text = it.name

View File

@ -2,6 +2,8 @@ package com.isolaatti.images
import com.isolaatti.connectivity.RetrofitClient import com.isolaatti.connectivity.RetrofitClient
import com.isolaatti.images.image_list.data.remote.ImagesApi import com.isolaatti.images.image_list.data.remote.ImagesApi
import com.isolaatti.images.image_list.data.repository.ImagesRepositoryImpl
import com.isolaatti.images.image_list.domain.repository.ImagesRepository
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
@ -14,4 +16,9 @@ class Module {
fun provideImagesApi(retrofitClient: RetrofitClient): ImagesApi { fun provideImagesApi(retrofitClient: RetrofitClient): ImagesApi {
return retrofitClient.client.create(ImagesApi::class.java) return retrofitClient.client.create(ImagesApi::class.java)
} }
@Provides
fun provideImagesRepository(imagesApi: ImagesApi): ImagesRepository {
return ImagesRepositoryImpl(imagesApi)
}
} }

View File

@ -5,5 +5,6 @@ data class ImageDto(
val userId: Int, val userId: Int,
val name: String, val name: String,
val squadId: String?, val squadId: String?,
val username: String,
val idOnFirebase: String val idOnFirebase: String
) )

View File

@ -13,9 +13,9 @@ import retrofit2.http.Path
import retrofit2.http.Query import retrofit2.http.Query
interface ImagesApi { interface ImagesApi {
@POST("images/of_user/{userId}") @GET("images/of_user/{userId}")
fun getImagesOfUser(@Path("userId") userId: Int, fun getImagesOfUser(@Path("userId") userId: Int,
@Query("lastId") lastId: String?): Call<List<ImageDto>> @Query("lastId") lastId: String?): Call<ImagesDto>
@POST("images/create") @POST("images/create")
@Multipart @Multipart

View File

@ -0,0 +1,5 @@
package com.isolaatti.images.image_list.data.remote
data class ImagesDto(
val data: List<ImageDto>
)

View File

@ -15,7 +15,7 @@ class ImagesRepositoryImpl @Inject constructor(private val imagesApi: ImagesApi)
val response = imagesApi.getImagesOfUser(userId, lastId).awaitResponse() val response = imagesApi.getImagesOfUser(userId, lastId).awaitResponse()
if(response.isSuccessful) { if(response.isSuccessful) {
val imagesDto = response.body() val imagesDto = response.body()
val images = imagesDto?.map { Image.fromDto(it) } val images = imagesDto?.data?.map { Image.fromDto(it) }
emit(Resource.Success(images)) emit(Resource.Success(images))

View File

@ -2,17 +2,19 @@ package com.isolaatti.images.image_list.domain.entity
import com.isolaatti.images.image_list.data.remote.ImageDto import com.isolaatti.images.image_list.data.remote.ImageDto
import com.isolaatti.utils.UrlGen import com.isolaatti.utils.UrlGen
import java.io.Serializable
data class Image( data class Image(
val id: String, val id: String,
val userId: Int, val userId: Int,
val name: String val name: String,
) { val username: String
): Serializable {
val imageUrl: String get() = UrlGen.imageUrl(id) val imageUrl: String get() = UrlGen.imageUrl(id)
val smallImageUrl : String get() = UrlGen.imageUrl(id, UrlGen.IMAGE_MODE_SMALL) val smallImageUrl : String get() = UrlGen.imageUrl(id, UrlGen.IMAGE_MODE_SMALL)
val reducedImageUrl: String get() = UrlGen.imageUrl(id, UrlGen.IMAGE_MODE_REDUCED) val reducedImageUrl: String get() = UrlGen.imageUrl(id, UrlGen.IMAGE_MODE_REDUCED)
companion object { companion object {
fun fromDto(imageDto: ImageDto) = Image(imageDto.id, imageDto.userId, imageDto.name) fun fromDto(imageDto: ImageDto) = Image(imageDto.id, imageDto.userId, imageDto.name, imageDto.username)
} }
} }

View File

@ -1,12 +1,29 @@
package com.isolaatti.images.image_list.presentation package com.isolaatti.images.image_list.presentation
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.isolaatti.images.image_list.domain.entity.Image
import com.isolaatti.images.image_list.domain.repository.ImagesRepository import com.isolaatti.images.image_list.domain.repository.ImagesRepository
import com.isolaatti.utils.Resource
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class ImageListViewModel @Inject constructor(private val imagesRepository: ImagesRepository) : ViewModel() { class ImageListViewModel @Inject constructor(private val imagesRepository: ImagesRepository) : ViewModel() {
val list: MutableLiveData<Resource<List<Image>>> = MutableLiveData()
fun loadNext(userId: Int) {
viewModelScope.launch {
imagesRepository.getImagesOfUser(userId, null).onEach {
list.postValue(it)
}.flowOn(Dispatchers.IO).launchIn(this)
}
}
} }

View File

@ -1,4 +1,44 @@
package com.isolaatti.images.image_list.presentation package com.isolaatti.images.image_list.presentation
class ImagesAdapter { import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.Adapter
import coil.load
import com.isolaatti.common.CoilImageLoader.imageLoader
import com.isolaatti.databinding.ImageItemBinding
import com.isolaatti.images.image_list.domain.entity.Image
class ImagesAdapter(private val imageOnClick: ((images: List<Image>, position: Int) -> Unit), private val itemWidth: Int) : Adapter<ImagesAdapter.ImageViewHolder>(){
private var data: List<Image> = listOf()
inner class ImageViewHolder(val imageItemBinding: ImageItemBinding) : RecyclerView.ViewHolder(imageItemBinding.root)
fun setData(data: List<Image>) {
this.data = data
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = ImageItemBinding.inflate(inflater)
binding.root.layoutParams = LinearLayout.LayoutParams(itemWidth, itemWidth)
return ImageViewHolder(binding)
}
override fun getItemCount(): Int {
return data.size
}
override fun onBindViewHolder(holder: ImageViewHolder, position: Int) {
val image = data[position]
holder.imageItemBinding.image.load(image.smallImageUrl, imageLoader)
holder.imageItemBinding.root.setOnClickListener {
imageOnClick(data, position)
}
}
} }

View File

@ -1,17 +1,57 @@
package com.isolaatti.images.image_list.ui package com.isolaatti.images.image_list.ui
import android.content.res.Resources
import android.net.Uri
import android.os.Bundle 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.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.widget.PopupMenu
import androidx.core.content.FileProvider
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.GridLayoutManager
import com.isolaatti.MyApplication
import com.isolaatti.R
import com.isolaatti.databinding.FragmentImagesBinding import com.isolaatti.databinding.FragmentImagesBinding
import com.isolaatti.images.image_list.domain.entity.Image
import com.isolaatti.images.image_list.presentation.ImageListViewModel
import com.isolaatti.images.image_list.presentation.ImagesAdapter
import com.isolaatti.images.picture_viewer.ui.PictureViewerActivity
import com.isolaatti.utils.Resource
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import dagger.hilt.android.lifecycle.HiltViewModel import java.io.File
import java.util.Calendar
@AndroidEntryPoint @AndroidEntryPoint
class ImagesFragment : Fragment() { class ImagesFragment : Fragment() {
lateinit var viewBinding: FragmentImagesBinding lateinit var viewBinding: FragmentImagesBinding
lateinit var adapter: ImagesAdapter
private val viewModel: ImageListViewModel by viewModels()
private val arguments: ImagesFragmentArgs by navArgs()
private var cameraPhotoUri: Uri? = null
private val imageOnClick: (images: List<Image>, position: Int) -> Unit = { images, position ->
PictureViewerActivity.startActivityWithImages(requireContext(), images.toTypedArray(), position)
}
private val choosePictureLauncher = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) {
// use uri
}
private val takePhotoLauncher = registerForActivityResult(ActivityResultContracts.TakePicture()) {
// use cameraPhotoUri if success
}
private fun makePhotoUri(): Uri {
val cacheFile = File(requireContext().filesDir, "temp_picture_${Calendar.getInstance().timeInMillis}")
return FileProvider.getUriForFile(requireContext(), "${MyApplication.myApp.packageName}.provider", cacheFile)
}
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
@ -25,5 +65,72 @@ class ImagesFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
when(arguments.source) {
SOURCE_SQUAD -> {}
SOURCE_PROFILE -> {
viewModel.loadNext(arguments.sourceId.toInt())
}
}
setupAdapter()
setupObservers()
setupListeners()
viewBinding.topAppBar.inflateMenu(R.menu.images_menu)
}
private fun setupListeners() {
viewBinding.topAppBar.setNavigationOnClickListener {
findNavController().popBackStack()
}
viewBinding.newPictureButton.setOnClickListener {
val popup = PopupMenu(requireContext(), it)
popup.menuInflater.inflate(R.menu.add_picture_menu, popup.menu)
popup.setOnMenuItemClickListener {
when(it.itemId) {
R.id.take_a_photo_menu_item -> {
cameraPhotoUri = makePhotoUri()
takePhotoLauncher.launch(cameraPhotoUri)
true
}
R.id.upload_a_picture_item -> {
choosePictureLauncher.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
true
}
else -> false
}
}
popup.show()
}
}
private fun setupAdapter() {
adapter = ImagesAdapter(imageOnClick, Resources.getSystem().displayMetrics.widthPixels/3)
viewBinding.recyclerView.layoutManager =
GridLayoutManager(requireContext(), 3, GridLayoutManager.VERTICAL, false)
viewBinding.recyclerView.adapter = adapter
}
private fun setupObservers() {
viewModel.list.observe(viewLifecycleOwner) { resource ->
when(resource) {
is Resource.Error -> {}
is Resource.Loading -> {}
is Resource.Success -> {
resource.data?.let {
adapter.setData(it)
}
}
}
}
}
companion object {
const val SOURCE_PROFILE = "source_profile"
const val SOURCE_SQUAD = "source_squads"
} }
} }

View File

@ -2,9 +2,10 @@ package com.isolaatti.images.picture_viewer.presentation
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.adapter.FragmentStateAdapter
import com.isolaatti.images.image_list.domain.entity.Image
import com.isolaatti.images.picture_viewer.ui.PictureViewerImageWrapperFragment import com.isolaatti.images.picture_viewer.ui.PictureViewerImageWrapperFragment
class PictureViewerViewPagerAdapter(fragment: Fragment, private val images: Array<String>) : FragmentStateAdapter(fragment) { class PictureViewerViewPagerAdapter(fragment: Fragment, private val images: Array<Image>) : FragmentStateAdapter(fragment) {
override fun getItemCount(): Int { override fun getItemCount(): Int {
return images.size return images.size
} }

View File

@ -5,6 +5,7 @@ import android.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.isolaatti.databinding.ActivityPictureViewerBinding import com.isolaatti.databinding.ActivityPictureViewerBinding
import com.isolaatti.images.image_list.domain.entity.Image
import com.isolaatti.images.picture_viewer.presentation.PictureViewerViewPagerAdapter import com.isolaatti.images.picture_viewer.presentation.PictureViewerViewPagerAdapter
class PictureViewerActivity : AppCompatActivity() { class PictureViewerActivity : AppCompatActivity() {
@ -21,12 +22,16 @@ class PictureViewerActivity : AppCompatActivity() {
companion object { companion object {
const val EXTRA_URLS = "urls" const val EXTRA_IMAGES = "images"
const val EXTRA_PROFILE_ID = "profileId" const val EXTRA_IMAGE_POSITiON = "position"
fun startActivityWithUrls(context: Context, urls: Array<String>) { fun startActivityWithImages(context: Context, images: Array<Image>, position: Int = 0) {
if(images.isEmpty()) {
return
}
val intent = Intent(context, PictureViewerActivity::class.java) val intent = Intent(context, PictureViewerActivity::class.java)
intent.putExtra(EXTRA_URLS, urls) intent.putExtra(EXTRA_IMAGES, images)
intent.putExtra(EXTRA_IMAGE_POSITiON, position)
context.startActivity(intent) context.startActivity(intent)
} }
} }

View File

@ -8,13 +8,14 @@ import androidx.fragment.app.Fragment
import coil.load import coil.load
import com.isolaatti.common.CoilImageLoader.imageLoader import com.isolaatti.common.CoilImageLoader.imageLoader
import com.isolaatti.databinding.FragmentTouchImageViewWrapperBinding import com.isolaatti.databinding.FragmentTouchImageViewWrapperBinding
import com.isolaatti.images.image_list.domain.entity.Image
import com.ortiz.touchview.OnTouchImageViewListener import com.ortiz.touchview.OnTouchImageViewListener
class PictureViewerImageWrapperFragment : Fragment() { class PictureViewerImageWrapperFragment : Fragment() {
private lateinit var binding: FragmentTouchImageViewWrapperBinding private lateinit var binding: FragmentTouchImageViewWrapperBinding
private var url: String? = null private var image: Image? = null
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
@ -23,7 +24,7 @@ class PictureViewerImageWrapperFragment : Fragment() {
): View { ): View {
binding = FragmentTouchImageViewWrapperBinding.inflate(inflater) binding = FragmentTouchImageViewWrapperBinding.inflate(inflater)
url = arguments?.getString(ARGUMENT_URL) image = arguments?.getSerializable(ARGUMENT_IMAGE) as Image
return binding.root return binding.root
} }
@ -42,17 +43,17 @@ class PictureViewerImageWrapperFragment : Fragment() {
url?.let { image?.let {
binding.touchImageView.load(it, imageLoader) binding.touchImageView.load(it.imageUrl, imageLoader)
} }
} }
companion object { companion object {
const val ARGUMENT_URL = "url" const val ARGUMENT_IMAGE = "image"
fun getInstance(url: String): PictureViewerImageWrapperFragment { fun getInstance(image: Image): PictureViewerImageWrapperFragment {
val fragment = PictureViewerImageWrapperFragment() val fragment = PictureViewerImageWrapperFragment()
fragment.arguments = Bundle().apply { fragment.arguments = Bundle().apply {
putString(ARGUMENT_URL, url) putSerializable(ARGUMENT_IMAGE, image)
} }
return fragment return fragment

View File

@ -5,12 +5,25 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.viewpager2.widget.ViewPager2
import com.isolaatti.databinding.FragmentMainPictureViewerBinding import com.isolaatti.databinding.FragmentMainPictureViewerBinding
import com.isolaatti.images.image_list.domain.entity.Image
import com.isolaatti.images.picture_viewer.presentation.PictureViewerViewPagerAdapter import com.isolaatti.images.picture_viewer.presentation.PictureViewerViewPagerAdapter
class PictureViewerMainFragment : Fragment() { class PictureViewerMainFragment : Fragment() {
private lateinit var binding: FragmentMainPictureViewerBinding private lateinit var binding: FragmentMainPictureViewerBinding
lateinit var images: Array<Image>
private val onPageChangeCallback = object: ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
binding.imageAuthor.text = images[position].username
binding.imageDescription.text = images[position].name
}
}
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
@ -24,12 +37,19 @@ class PictureViewerMainFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
val url = requireActivity().intent.extras?.getStringArray(PictureViewerActivity.EXTRA_URLS) images = requireActivity().intent.extras?.getSerializable(PictureViewerActivity.EXTRA_IMAGES) as Array<Image>
val position = requireActivity().intent.extras?.getInt(PictureViewerActivity.EXTRA_IMAGE_POSITiON) ?: 0
url?.let { val adapter = PictureViewerViewPagerAdapter(this, images)
val adapter = PictureViewerViewPagerAdapter(this, it)
binding.viewpager.adapter = adapter binding.viewpager.adapter = adapter
binding.viewpager.setCurrentItem(position, false)
binding.viewpager.registerOnPageChangeCallback(onPageChangeCallback)
binding.imageDescription.text = images[position].name
binding.imageAuthor.text = images[position].username
} }
override fun onDestroyView() {
super.onDestroyView()
binding.viewpager.unregisterOnPageChangeCallback(onPageChangeCallback)
} }
fun enableViewPagerUserInput(enabled: Boolean) { fun enableViewPagerUserInput(enabled: Boolean) {

View File

@ -31,6 +31,7 @@ import com.isolaatti.common.options_bottom_sheet.domain.OptionClicked
import com.isolaatti.common.options_bottom_sheet.domain.Options import com.isolaatti.common.options_bottom_sheet.domain.Options
import com.isolaatti.common.options_bottom_sheet.presentation.BottomSheetPostOptionsViewModel import com.isolaatti.common.options_bottom_sheet.presentation.BottomSheetPostOptionsViewModel
import com.isolaatti.common.options_bottom_sheet.ui.BottomSheetPostOptionsFragment import com.isolaatti.common.options_bottom_sheet.ui.BottomSheetPostOptionsFragment
import com.isolaatti.images.image_list.ui.ImagesFragment
import com.isolaatti.images.picture_viewer.ui.PictureViewerActivity import com.isolaatti.images.picture_viewer.ui.PictureViewerActivity
import com.isolaatti.posting.posts.domain.entity.Post import com.isolaatti.posting.posts.domain.entity.Post
import com.isolaatti.posting.posts.presentation.CreatePostContract import com.isolaatti.posting.posts.presentation.CreatePostContract
@ -149,7 +150,7 @@ class ProfileMainFragment : Fragment() {
Options.Option.OPTION_PROFILE_PHOTO_VIEW_PHOTO -> { Options.Option.OPTION_PROFILE_PHOTO_VIEW_PHOTO -> {
val profilePictureUrl = profile?.profilePictureUrl val profilePictureUrl = profile?.profilePictureUrl
if(profilePictureUrl != null) { if(profilePictureUrl != null) {
PictureViewerActivity.startActivityWithUrls(requireContext(), arrayOf(profilePictureUrl)) //PictureViewerActivity.startActivityWithUrls(requireContext(), arrayOf(profilePictureUrl))
} }
} }
} }
@ -217,8 +218,14 @@ class ProfileMainFragment : Fragment() {
true true
} }
R.id.images_menu_item -> { R.id.images_menu_item -> {
findNavController().navigate(ProfileMainFragmentDirections.actionDiscussionsFragmentToImagesFragment()) if(userId != null) {
findNavController().navigate(
ProfileMainFragmentDirections.actionDiscussionsFragmentToImagesFragment(ImagesFragment.SOURCE_PROFILE, userId.toString())
)
true true
} else {
false
}
} }
else -> { false } else -> { false }
} }

View File

@ -1,4 +1,4 @@
<vector android:height="24dp" android:tint="#000000" <vector android:height="24dp" android:tint="@color/on_surface"
android:viewportHeight="24" android:viewportWidth="24" android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/> <path android:fillColor="@android:color/white" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>

View File

@ -2,6 +2,7 @@
<FrameLayout <FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" 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">
<androidx.fragment.app.FragmentContainerView <androidx.fragment.app.FragmentContainerView

View File

@ -21,4 +21,13 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" /> app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/new_picture_button"
android:layout_gravity="bottom|end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
app:srcCompat="@drawable/baseline_add_24"
android:contentDescription="@string/upload_a_picture" />
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
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">
<androidx.viewpager2.widget.ViewPager2 <androidx.viewpager2.widget.ViewPager2
@ -7,4 +8,29 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@color/black"/> android:background="@color/black"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="vertical"
android:background="@color/translucent_black"
android:padding="16dp">
<TextView
android:id="@+id/image_author"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
android:textSize="16sp"
android:textStyle="bold"
tools:text="Erik" />
<TextView
android:id="@+id/image_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
android:textSize="16sp"
tools:text="Image description" />
</LinearLayout>
</FrameLayout> </FrameLayout>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/take_a_photo_menu_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:title="@string/take_a_photo" />
<item
android:id="@+id/upload_a_picture_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:title="@string/upload_a_picture" />
</menu>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/delete_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:icon="@drawable/baseline_delete_24"
app:showAsAction="always"
android:title="@string/delete" />
</menu>

View File

@ -36,7 +36,14 @@
<fragment <fragment
android:id="@+id/imagesFragment" android:id="@+id/imagesFragment"
android:name="com.isolaatti.images.image_list.ui.ImagesFragment" android:name="com.isolaatti.images.image_list.ui.ImagesFragment"
android:label="ImagesFragment" /> android:label="ImagesFragment" >
<argument
android:name="source"
app:argType="string" />
<argument
android:name="sourceId"
app:argType="string" />
</fragment>
<fragment <fragment
android:id="@+id/blockProfileFragment" android:id="@+id/blockProfileFragment"
android:name="com.isolaatti.profile.ui.BlockProfileFragment" android:name="com.isolaatti.profile.ui.BlockProfileFragment"

View File

@ -6,4 +6,5 @@
<color name="on_surface">#000000</color> <color name="on_surface">#000000</color>
<color name="danger">#BA0606</color> <color name="danger">#BA0606</color>
<color name="black">#000000</color> <color name="black">#000000</color>
<color name="translucent_black">#9A000000</color>
</resources> </resources>

View File

@ -115,4 +115,6 @@
<string name="display_name_invalid_feedback">Please provide a name. This does not have to be unique and can be your real name or not.</string> <string name="display_name_invalid_feedback">Please provide a name. This does not have to be unique and can be your real name or not.</string>
<string name="validation_error">Validation error</string> <string name="validation_error">Validation error</string>
<string name="email_used">Email is in use already</string> <string name="email_used">Email is in use already</string>
<string name="upload_a_picture">Upload a picture</string>
<string name="take_a_photo">Take a photo</string>
</resources> </resources>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path
name="files"
path="."/>
</paths>