From a130e25ba40ef8774c7a500570f8e9a5b46d8a60 Mon Sep 17 00:00:00 2001 From: etudiant Date: Fri, 10 Feb 2023 12:18:33 +0100 Subject: [PATCH] andro --- .DS_Store | Bin 6148 -> 6148 bytes MyAndroid/.gitignore | 15 ++ MyAndroid/app/.gitignore | 1 + MyAndroid/app/build.gradle | 91 +++++++++ MyAndroid/app/proguard-rules.pro | 21 ++ .../iut/myandroid/ExampleInstrumentedTest.kt | 24 +++ MyAndroid/app/src/main/AndroidManifest.xml | 36 ++++ .../src/main/java/fr/iut/myandroid/Dao.java | 5 + .../java/fr/iut/myandroid/MainActivity.kt | 28 +++ .../java/fr/iut/myandroid/api/ReponseApi.kt | 7 + .../java/fr/iut/myandroid/api/UnsplashApi.kt | 25 +++ .../fr/iut/myandroid/data/PhotoUnsplash.kt | 35 ++++ .../iut/myandroid/data/UnsplashPageSource.kt | 35 ++++ .../iut/myandroid/data/UnsplashRepository.kt | 24 +++ .../java/fr/iut/myandroid/di/Appmodule.kt | 34 ++++ .../src/main/java/fr/iut/myandroid/search.kt | 8 + .../ui/Mongalery/UnsplashPhotoAdapter.kt | 73 +++++++ .../Mongalery/UnsplashphotoloaStateAdapter.kt | 43 ++++ .../myandroid/ui/Mongalery/galeryfragment.kt | 106 ++++++++++ .../fr/iut/myandroid/ui/details/DFragment.kt | 70 +++++++ .../fr/iut/myandroid/vm/GaleryViewModel.kt | 38 ++++ .../drawable-v24/ic_launcher_foreground.xml | 30 +++ .../app/src/main/res/drawable-v24/ic_user.xml | 10 + .../app/src/main/res/drawable/gradient.xml | 11 ++ .../app/src/main/res/drawable/ic_error.xml | 10 + .../res/drawable/ic_launcher_background.xml | 170 ++++++++++++++++ .../app/src/main/res/drawable/ic_search.xml | 10 + .../app/src/main/res/layout/activity_main.xml | 17 ++ .../src/main/res/layout/detail_fragment.xml | 60 ++++++ .../src/main/res/layout/fragment_galery.xml | 52 +++++ .../main/res/layout/item_unsplash_photo.xml | 33 ++++ .../unsplash_photo_load_state_footer.xml | 26 +++ .../app/src/main/res/menu/menu_galleryy.xml | 10 + .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + .../src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 1404 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 2898 bytes .../src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 982 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 1772 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 1900 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 3918 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 2884 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 5914 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 3844 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 7778 bytes .../app/src/main/res/navigation/nav_graph.xml | 27 +++ .../app/src/main/res/values-night/themes.xml | 16 ++ MyAndroid/app/src/main/res/values/colors.xml | 10 + MyAndroid/app/src/main/res/values/strings.xml | 3 + MyAndroid/app/src/main/res/values/themes.xml | 16 ++ .../app/src/main/res/xml/backup_rules.xml | 13 ++ .../main/res/xml/data_extraction_rules.xml | 19 ++ .../java/fr/iut/myandroid/ExampleUnitTest.kt | 17 ++ MyAndroid/build.gradle | 49 +++++ MyAndroid/gradle.properties | 23 +++ MyAndroid/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + MyAndroid/gradlew | 185 ++++++++++++++++++ MyAndroid/gradlew.bat | 89 +++++++++ MyAndroid/settings.gradle | 16 ++ 60 files changed, 1657 insertions(+) create mode 100644 MyAndroid/.gitignore create mode 100644 MyAndroid/app/.gitignore create mode 100644 MyAndroid/app/build.gradle create mode 100644 MyAndroid/app/proguard-rules.pro create mode 100644 MyAndroid/app/src/androidTest/java/fr/iut/myandroid/ExampleInstrumentedTest.kt create mode 100644 MyAndroid/app/src/main/AndroidManifest.xml create mode 100644 MyAndroid/app/src/main/java/fr/iut/myandroid/Dao.java create mode 100644 MyAndroid/app/src/main/java/fr/iut/myandroid/MainActivity.kt create mode 100644 MyAndroid/app/src/main/java/fr/iut/myandroid/api/ReponseApi.kt create mode 100644 MyAndroid/app/src/main/java/fr/iut/myandroid/api/UnsplashApi.kt create mode 100644 MyAndroid/app/src/main/java/fr/iut/myandroid/data/PhotoUnsplash.kt create mode 100644 MyAndroid/app/src/main/java/fr/iut/myandroid/data/UnsplashPageSource.kt create mode 100644 MyAndroid/app/src/main/java/fr/iut/myandroid/data/UnsplashRepository.kt create mode 100644 MyAndroid/app/src/main/java/fr/iut/myandroid/di/Appmodule.kt create mode 100644 MyAndroid/app/src/main/java/fr/iut/myandroid/search.kt create mode 100644 MyAndroid/app/src/main/java/fr/iut/myandroid/ui/Mongalery/UnsplashPhotoAdapter.kt create mode 100644 MyAndroid/app/src/main/java/fr/iut/myandroid/ui/Mongalery/UnsplashphotoloaStateAdapter.kt create mode 100644 MyAndroid/app/src/main/java/fr/iut/myandroid/ui/Mongalery/galeryfragment.kt create mode 100644 MyAndroid/app/src/main/java/fr/iut/myandroid/ui/details/DFragment.kt create mode 100644 MyAndroid/app/src/main/java/fr/iut/myandroid/vm/GaleryViewModel.kt create mode 100644 MyAndroid/app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 MyAndroid/app/src/main/res/drawable-v24/ic_user.xml create mode 100644 MyAndroid/app/src/main/res/drawable/gradient.xml create mode 100644 MyAndroid/app/src/main/res/drawable/ic_error.xml create mode 100644 MyAndroid/app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 MyAndroid/app/src/main/res/drawable/ic_search.xml create mode 100644 MyAndroid/app/src/main/res/layout/activity_main.xml create mode 100644 MyAndroid/app/src/main/res/layout/detail_fragment.xml create mode 100644 MyAndroid/app/src/main/res/layout/fragment_galery.xml create mode 100644 MyAndroid/app/src/main/res/layout/item_unsplash_photo.xml create mode 100644 MyAndroid/app/src/main/res/layout/unsplash_photo_load_state_footer.xml create mode 100644 MyAndroid/app/src/main/res/menu/menu_galleryy.xml create mode 100644 MyAndroid/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 MyAndroid/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 MyAndroid/app/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 MyAndroid/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 MyAndroid/app/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 MyAndroid/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 MyAndroid/app/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 MyAndroid/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 MyAndroid/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 MyAndroid/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 MyAndroid/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 MyAndroid/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 MyAndroid/app/src/main/res/navigation/nav_graph.xml create mode 100644 MyAndroid/app/src/main/res/values-night/themes.xml create mode 100644 MyAndroid/app/src/main/res/values/colors.xml create mode 100644 MyAndroid/app/src/main/res/values/strings.xml create mode 100644 MyAndroid/app/src/main/res/values/themes.xml create mode 100644 MyAndroid/app/src/main/res/xml/backup_rules.xml create mode 100644 MyAndroid/app/src/main/res/xml/data_extraction_rules.xml create mode 100644 MyAndroid/app/src/test/java/fr/iut/myandroid/ExampleUnitTest.kt create mode 100644 MyAndroid/build.gradle create mode 100644 MyAndroid/gradle.properties create mode 100644 MyAndroid/gradle/wrapper/gradle-wrapper.jar create mode 100644 MyAndroid/gradle/wrapper/gradle-wrapper.properties create mode 100755 MyAndroid/gradlew create mode 100644 MyAndroid/gradlew.bat create mode 100644 MyAndroid/settings.gradle diff --git a/.DS_Store b/.DS_Store index d1e53c38c9df1f135e2ec13ce406fa49ed2030fc..e0b6d7c5674da12ac75896fbc152edb292cca603 100644 GIT binary patch delta 172 zcmZoMXfc=|#>B!ku~2NHo+2an#(>?7i&&T#xi|ALZD(}$WvFCuWXNMkVJKqAXUJqo z@yy9jPRhwoVqjnpU|?XB1=4!|!2rl&VBloH&@tJEse!}T#8gMY$lP-B6()OOEQ&U7 lVpeC|%+A5j0d&jekIdhhC-aLqaxgM5FoBHS93irX831>KDGLAq delta 68 zcmZoMXfc=|#>B)qu~2NHo+2a1#(>?7j2xSJShh26{>UcAxUoTxc{4i)KL=3FW + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MyAndroid/app/src/main/java/fr/iut/myandroid/Dao.java b/MyAndroid/app/src/main/java/fr/iut/myandroid/Dao.java new file mode 100644 index 0000000..5c0d9f4 --- /dev/null +++ b/MyAndroid/app/src/main/java/fr/iut/myandroid/Dao.java @@ -0,0 +1,5 @@ +package fr.iut.myandroid; + +public interface Dao { + +} diff --git a/MyAndroid/app/src/main/java/fr/iut/myandroid/MainActivity.kt b/MyAndroid/app/src/main/java/fr/iut/myandroid/MainActivity.kt new file mode 100644 index 0000000..d578d01 --- /dev/null +++ b/MyAndroid/app/src/main/java/fr/iut/myandroid/MainActivity.kt @@ -0,0 +1,28 @@ +package fr.iut.myandroid + +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import androidx.navigation.NavController +import androidx.navigation.fragment.NavHostFragment +import androidx.navigation.fragment.findNavController +import androidx.navigation.ui.AppBarConfiguration +import androidx.navigation.ui.setupActionBarWithNavController +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class MainActivity : AppCompatActivity() { + private lateinit var navController: NavController + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + + val navHostController=supportFragmentManager.findFragmentById(R.id.nav_host_fragment_main) as NavHostFragment + navController=navHostController.findNavController() + val appBarConfiguration= AppBarConfiguration(navController.graph) + setupActionBarWithNavController(navController,appBarConfiguration) + } + + override fun onSupportNavigateUp(): Boolean { + return navController.navigateUp() || super.onSupportNavigateUp() + } +} \ No newline at end of file diff --git a/MyAndroid/app/src/main/java/fr/iut/myandroid/api/ReponseApi.kt b/MyAndroid/app/src/main/java/fr/iut/myandroid/api/ReponseApi.kt new file mode 100644 index 0000000..1b3e6ee --- /dev/null +++ b/MyAndroid/app/src/main/java/fr/iut/myandroid/api/ReponseApi.kt @@ -0,0 +1,7 @@ +package fr.iut.myandroid.api +import fr.iut.myandroid.data.PhotoUnsplash + +data class ResponseApi( + val results : List + +) \ No newline at end of file diff --git a/MyAndroid/app/src/main/java/fr/iut/myandroid/api/UnsplashApi.kt b/MyAndroid/app/src/main/java/fr/iut/myandroid/api/UnsplashApi.kt new file mode 100644 index 0000000..94fd4b0 --- /dev/null +++ b/MyAndroid/app/src/main/java/fr/iut/myandroid/api/UnsplashApi.kt @@ -0,0 +1,25 @@ +package fr.iut.myandroid.api + +import fr.iut.myandroid.BuildConfig +import fr.iut.myandroid.BuildConfig.APPLICATION_ID +import retrofit2.http.GET +import retrofit2.http.Headers +import retrofit2.http.Query + + +interface UnsplashApi { + + companion object{ + const val CLIENT_ID ="DqTWq4IuTHgzVZB8T60q33hoJOOK9ssGEbUl6Eeu6p4" + const val BASE_URL = "https://api.unsplash.com/" + } + @Headers("Accept-Version: v1", + "Authorization:Client-ID $CLIENT_ID") + @GET("search/photos") + + suspend fun searchphoto( + @Query("query") query: String, + @Query("page") page : Int, + @Query("per_page") per_page : Int + ):ResponseApi +} \ No newline at end of file diff --git a/MyAndroid/app/src/main/java/fr/iut/myandroid/data/PhotoUnsplash.kt b/MyAndroid/app/src/main/java/fr/iut/myandroid/data/PhotoUnsplash.kt new file mode 100644 index 0000000..eb5c065 --- /dev/null +++ b/MyAndroid/app/src/main/java/fr/iut/myandroid/data/PhotoUnsplash.kt @@ -0,0 +1,35 @@ +package fr.iut.myandroid.data + + + +import android.os.Parcelable +import fr.iut.myandroid.api.ResponseApi +import fr.iut.myandroid.api.UnsplashApi +import kotlinx.android.parcel.Parcelize + + +@Parcelize +data class PhotoUnsplash( + val id: String, + val description: String?, + val urls: UnsplashPhotoUrls, + val user: UnsplashUser +) : Parcelable { + + @Parcelize + data class UnsplashPhotoUrls( + val raw: String, + val full: String, + val regular: String, + val small: String, + val thumb: String, + ) : Parcelable + + @Parcelize + data class UnsplashUser( + val name: String, + val username: String + ) : Parcelable { + val attributionUrl get() = "https://unsplash.com/$username?utm_source=ImageSearchApp&utm_medium=referral" + } +} diff --git a/MyAndroid/app/src/main/java/fr/iut/myandroid/data/UnsplashPageSource.kt b/MyAndroid/app/src/main/java/fr/iut/myandroid/data/UnsplashPageSource.kt new file mode 100644 index 0000000..229750d --- /dev/null +++ b/MyAndroid/app/src/main/java/fr/iut/myandroid/data/UnsplashPageSource.kt @@ -0,0 +1,35 @@ +package fr.iut.myandroid.data + +import androidx.paging.PagingSource +import fr.iut.myandroid.api.ResponseApi +import fr.iut.myandroid.api.UnsplashApi +import retrofit2.HttpException +import java.io.IOException + +private const val UNSPLASH_START_PAGE_INDEX=1 +class UnsplashPageSource ( + private val UnsplashApi:UnsplashApi, + private val query:String):PagingSource() { + + override suspend fun load(params: LoadParams): LoadResult + { + val position = params.key ?: UNSPLASH_START_PAGE_INDEX + + return try + { + val response = UnsplashApi.searchphoto(query, position, params.loadSize) + val photos =response.results + + LoadResult.Page( + data = photos, + prevKey = if (position == UNSPLASH_START_PAGE_INDEX) null else position - 1, + nextKey = if (photos.isEmpty()) null else position + 1 + ) + } catch (exception: IOException) { + LoadResult.Error(exception) + } catch (exception: HttpException) { + LoadResult.Error(exception) + } + } + + } \ No newline at end of file diff --git a/MyAndroid/app/src/main/java/fr/iut/myandroid/data/UnsplashRepository.kt b/MyAndroid/app/src/main/java/fr/iut/myandroid/data/UnsplashRepository.kt new file mode 100644 index 0000000..ab1576f --- /dev/null +++ b/MyAndroid/app/src/main/java/fr/iut/myandroid/data/UnsplashRepository.kt @@ -0,0 +1,24 @@ +package fr.iut.myandroid.data + +import androidx.paging.Pager +import androidx.paging.PagingConfig +import androidx.paging.liveData +import fr.iut.myandroid.api.UnsplashApi +import fr.iut.myandroid.data.UnsplashPageSource +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class UnsplashRepository @Inject constructor (private val unsplashApi: UnsplashApi ) { + + fun getSearchResults(query: String) = + Pager( + config = PagingConfig( + pageSize = 10, + maxSize = 100, + enablePlaceholders = false + ), + pagingSourceFactory = {UnsplashPageSource(unsplashApi, query) } + ).liveData + +} \ No newline at end of file diff --git a/MyAndroid/app/src/main/java/fr/iut/myandroid/di/Appmodule.kt b/MyAndroid/app/src/main/java/fr/iut/myandroid/di/Appmodule.kt new file mode 100644 index 0000000..fecaadc --- /dev/null +++ b/MyAndroid/app/src/main/java/fr/iut/myandroid/di/Appmodule.kt @@ -0,0 +1,34 @@ +package fr.iut.myandroid.di + +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.components.ApplicationComponent +import fr.iut.myandroid.api.UnsplashApi + +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import javax.inject.Singleton + + + +@Module +@InstallIn(ApplicationComponent::class) +object Appmodule { + @Provides + @Singleton + fun provideRetrofit():Retrofit=Retrofit.Builder() + .baseUrl(UnsplashApi.BASE_URL) + .addConverterFactory(GsonConverterFactory.create()) + .build() + + +@Provides +@Singleton +fun provideUnsplashApi(retrofit: Retrofit): UnsplashApi = + retrofit.create(UnsplashApi::class.java) + + + + +} \ No newline at end of file diff --git a/MyAndroid/app/src/main/java/fr/iut/myandroid/search.kt b/MyAndroid/app/src/main/java/fr/iut/myandroid/search.kt new file mode 100644 index 0000000..5c1ca76 --- /dev/null +++ b/MyAndroid/app/src/main/java/fr/iut/myandroid/search.kt @@ -0,0 +1,8 @@ +package fr.iut.myandroid + +import android.app.Application +import dagger.hilt.android.HiltAndroidApp + +@HiltAndroidApp +class search :Application(){ +} \ No newline at end of file diff --git a/MyAndroid/app/src/main/java/fr/iut/myandroid/ui/Mongalery/UnsplashPhotoAdapter.kt b/MyAndroid/app/src/main/java/fr/iut/myandroid/ui/Mongalery/UnsplashPhotoAdapter.kt new file mode 100644 index 0000000..8abaa9a --- /dev/null +++ b/MyAndroid/app/src/main/java/fr/iut/myandroid/ui/Mongalery/UnsplashPhotoAdapter.kt @@ -0,0 +1,73 @@ +package fr.iut.myandroid.ui.Mongalery + + import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.paging.PagingDataAdapter +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions +import fr.iut.myandroid.R +import fr.iut.myandroid.data.PhotoUnsplash +import fr.iut.myandroid.databinding.ItemUnsplashPhotoBinding + +class UnsplashPhotoAdapter (private val listner :OnItemClickListener): + PagingDataAdapter(PHOTO_COMPARATOR) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PhotoViewHolder { + val binding = + ItemUnsplashPhotoBinding.inflate(LayoutInflater.from(parent.context), parent, false) + + return PhotoViewHolder(binding) + } + + override fun onBindViewHolder(holder: PhotoViewHolder, position: Int) { + val currentItem = getItem(position) + if (currentItem != null) { + holder.bind(currentItem) + } + } + + inner class PhotoViewHolder(private val binding: ItemUnsplashPhotoBinding) : + RecyclerView.ViewHolder(binding.root) { + + init { + binding.root.setOnClickListener { + val position = bindingAdapterPosition + if (position != RecyclerView.NO_POSITION) { + val item = getItem(position) + if (item != null) { + listner.onItemClick(item) + } + } + } + } + + fun bind(photo: PhotoUnsplash) { + binding.apply { + Glide.with(itemView) + .load(photo.urls.regular) + .centerCrop() + .transition(DrawableTransitionOptions.withCrossFade()) + .error(R.drawable.ic_error) + .into(imageView) + + textViewUserName.text = photo.user.username + } + } + } + + interface OnItemClickListener { + fun onItemClick(photo: PhotoUnsplash) + } + + companion object { + private val PHOTO_COMPARATOR = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: PhotoUnsplash, newItem: PhotoUnsplash) = + oldItem.id == newItem.id + + override fun areContentsTheSame(oldItem: PhotoUnsplash, newItem: PhotoUnsplash) = + oldItem == newItem + } + } +} \ No newline at end of file diff --git a/MyAndroid/app/src/main/java/fr/iut/myandroid/ui/Mongalery/UnsplashphotoloaStateAdapter.kt b/MyAndroid/app/src/main/java/fr/iut/myandroid/ui/Mongalery/UnsplashphotoloaStateAdapter.kt new file mode 100644 index 0000000..1594674 --- /dev/null +++ b/MyAndroid/app/src/main/java/fr/iut/myandroid/ui/Mongalery/UnsplashphotoloaStateAdapter.kt @@ -0,0 +1,43 @@ +package fr.iut.myandroid.ui.Mongalery + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.core.view.isVisible +import androidx.paging.LoadState +import androidx.paging.LoadStateAdapter +import androidx.recyclerview.widget.RecyclerView +import fr.iut.myandroid.databinding.UnsplashPhotoLoadStateFooterBinding + +class UnsplashphotoloaStateAdapter (private val retry: () -> Unit) : + LoadStateAdapter() { + + override fun onCreateViewHolder(parent: ViewGroup, loadState: LoadState): LoadStateViewHolder { + val binding = UnsplashPhotoLoadStateFooterBinding.inflate( + LayoutInflater.from(parent.context),parent, + false) + + return LoadStateViewHolder(binding) + } + + override fun onBindViewHolder(holder: LoadStateViewHolder, loadState: LoadState) { + holder.bind(loadState) + } + + inner class LoadStateViewHolder(private val binding: UnsplashPhotoLoadStateFooterBinding) : + RecyclerView.ViewHolder(binding.root) { + + init { + binding.buttonRetry.setOnClickListener { + retry.invoke() + } + } + + fun bind(loadState: LoadState) { + binding.apply { + progressBar.isVisible = loadState is LoadState.Loading + buttonRetry.isVisible = loadState !is LoadState.Loading + textViewError.isVisible = loadState !is LoadState.Loading + } + } + } +} diff --git a/MyAndroid/app/src/main/java/fr/iut/myandroid/ui/Mongalery/galeryfragment.kt b/MyAndroid/app/src/main/java/fr/iut/myandroid/ui/Mongalery/galeryfragment.kt new file mode 100644 index 0000000..20f98fd --- /dev/null +++ b/MyAndroid/app/src/main/java/fr/iut/myandroid/ui/Mongalery/galeryfragment.kt @@ -0,0 +1,106 @@ +package fr.iut.myandroid.ui.Mongalery + +import android.os.Bundle +import android.view.Menu +import android.view.MenuInflater +import android.view.View +import androidx.appcompat.widget.SearchView +import androidx.core.view.isVisible +import androidx.fragment.app.Fragment +import dagger.hilt.android.AndroidEntryPoint +import fr.iut.myandroid.R +import androidx.fragment.app.viewModels +import androidx.navigation.fragment.findNavController +import androidx.paging.LoadState +import fr.iut.myandroid.data.PhotoUnsplash +import fr.iut.myandroid.databinding.FragmentGaleryBinding +import fr.iut.myandroid.vm.GaleryViewModel + +@AndroidEntryPoint +class galeryfragment : Fragment(R.layout.fragment_galery),UnsplashPhotoAdapter.OnItemClickListener { + private val viewModel by viewModels() + private var _binding: FragmentGaleryBinding? = null + private val binding get() = _binding!! + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + _binding = FragmentGaleryBinding.bind(view) + + val adapter = UnsplashPhotoAdapter(this) + + binding.apply { + recyclerView.setHasFixedSize(true) + recyclerView.itemAnimator = null + recyclerView.adapter = adapter.withLoadStateHeaderAndFooter( + header = UnsplashphotoloaStateAdapter { adapter.retry() }, + footer = UnsplashphotoloaStateAdapter { adapter.retry() }, + ) + buttonRetry.setOnClickListener { + adapter.retry() + } + } + + viewModel.photos.observe(viewLifecycleOwner) { + adapter.submitData(viewLifecycleOwner.lifecycle, it) + } + + adapter.addLoadStateListener { loadState -> + binding.apply { + progressBar.isVisible = loadState.source.refresh is LoadState.Loading + recyclerView.isVisible = loadState.source.refresh is LoadState.NotLoading + buttonRetry.isVisible = loadState.source.refresh is LoadState.Error + textViewError.isVisible = loadState.source.refresh is LoadState.Error + + // empty view + if (loadState.source.refresh is LoadState.NotLoading && + loadState.append.endOfPaginationReached && + adapter.itemCount < 1) { + recyclerView.isVisible = false + textViewEmpty.isVisible = true + } else { + textViewEmpty.isVisible = false + } + } + } + + setHasOptionsMenu(true) + } + + override fun onItemClick(photo: PhotoUnsplash) { + + val action = galeryfragmentDirections.actionGalleryFragmentToDFragment2(photo) + findNavController().navigate(action) + + } + + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + super.onCreateOptionsMenu(menu, inflater) + + inflater.inflate(R.menu.menu_galleryy, menu) + + val searchItem = menu.findItem(R.id.action_search) + val searchView = searchItem.actionView as SearchView + + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String?): Boolean { + + if (query != null) { + binding.recyclerView.scrollToPosition(0) + viewModel.searchPhotos(query) + searchView.clearFocus() + } + return true + } + + override fun onQueryTextChange(newText: String?): Boolean { + return true + } + }) + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} diff --git a/MyAndroid/app/src/main/java/fr/iut/myandroid/ui/details/DFragment.kt b/MyAndroid/app/src/main/java/fr/iut/myandroid/ui/details/DFragment.kt new file mode 100644 index 0000000..e73f876 --- /dev/null +++ b/MyAndroid/app/src/main/java/fr/iut/myandroid/ui/details/DFragment.kt @@ -0,0 +1,70 @@ +package fr.iut.myandroid.ui.details + +import android.content.Intent +import android.graphics.drawable.Drawable +import android.net.Uri +import android.os.Bundle +import android.view.View +import androidx.core.view.isVisible +import androidx.fragment.app.Fragment +import androidx.navigation.fragment.navArgs +import com.bumptech.glide.Glide +import com.bumptech.glide.load.DataSource +import com.bumptech.glide.load.engine.GlideException +import com.bumptech.glide.request.RequestListener +import com.bumptech.glide.request.target.Target +import fr.iut.myandroid.R +import fr.iut.myandroid.databinding.DetailFragmentBinding + +class DFragment :Fragment(R.layout.detail_fragment) { + private val args by navArgs() + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + val binding = DetailFragmentBinding.bind(view) + + binding.apply { + val photo = args.photo + + Glide.with(this@DFragment) + .load(photo.urls.full) + .error(R.drawable.ic_error) + .listener(object : RequestListener { + override fun onLoadFailed( + e: GlideException?, + model: Any?, + target: Target?, + isFirstResource: Boolean + ): Boolean { + progressBar.isVisible = false + return false + } + + override fun onResourceReady( + resource: Drawable?, + model: Any?, + target: Target?, + dataSource: DataSource?, + isFirstResource: Boolean + ): Boolean { + progressBar.isVisible = false + textViewCreator.isVisible = true + textViewDescription.isVisible = photo.description != null + return false + } + }) + .into(imageView) + + textViewDescription.text = photo.description + + val uri = Uri.parse(photo.user.attributionUrl) + val intent = Intent(Intent.ACTION_VIEW, uri) + + textViewCreator.apply { + text = "Photo by ${photo.user.name} on Unsplash" + setOnClickListener { + context.startActivity(intent) + } + paint.isUnderlineText = true + } + } + } +} \ No newline at end of file diff --git a/MyAndroid/app/src/main/java/fr/iut/myandroid/vm/GaleryViewModel.kt b/MyAndroid/app/src/main/java/fr/iut/myandroid/vm/GaleryViewModel.kt new file mode 100644 index 0000000..24e7ec9 --- /dev/null +++ b/MyAndroid/app/src/main/java/fr/iut/myandroid/vm/GaleryViewModel.kt @@ -0,0 +1,38 @@ +package fr.iut.myandroid.vm +import androidx.hilt.Assisted +import androidx.hilt.lifecycle.ViewModelInject +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.lifecycle.switchMap +import androidx.lifecycle.viewModelScope +import androidx.paging.cachedIn +import fr.iut.myandroid.data.UnsplashRepository + + + + + + +class GaleryViewModel @ViewModelInject constructor + ( + private val repository: UnsplashRepository, + @Assisted state: SavedStateHandle +):ViewModel() +{ + private val currentQuery=state.getLiveData(CURRENT_QUERY, DEFAULT_QUERY) + val photos = currentQuery.switchMap { queryString -> + repository.getSearchResults(queryString).cachedIn(viewModelScope) + } + + fun searchPhotos(query: String) { + currentQuery.value = query + } + + companion object { + private const val CURRENT_QUERY="current_query" + private const val DEFAULT_QUERY = "chien" + } +} + + + diff --git a/MyAndroid/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/MyAndroid/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/MyAndroid/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/MyAndroid/app/src/main/res/drawable-v24/ic_user.xml b/MyAndroid/app/src/main/res/drawable-v24/ic_user.xml new file mode 100644 index 0000000..61b9bbc --- /dev/null +++ b/MyAndroid/app/src/main/res/drawable-v24/ic_user.xml @@ -0,0 +1,10 @@ + + + diff --git a/MyAndroid/app/src/main/res/drawable/gradient.xml b/MyAndroid/app/src/main/res/drawable/gradient.xml new file mode 100644 index 0000000..5d3bdfd --- /dev/null +++ b/MyAndroid/app/src/main/res/drawable/gradient.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/MyAndroid/app/src/main/res/drawable/ic_error.xml b/MyAndroid/app/src/main/res/drawable/ic_error.xml new file mode 100644 index 0000000..138c8c6 --- /dev/null +++ b/MyAndroid/app/src/main/res/drawable/ic_error.xml @@ -0,0 +1,10 @@ + + + diff --git a/MyAndroid/app/src/main/res/drawable/ic_launcher_background.xml b/MyAndroid/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/MyAndroid/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MyAndroid/app/src/main/res/drawable/ic_search.xml b/MyAndroid/app/src/main/res/drawable/ic_search.xml new file mode 100644 index 0000000..efaa193 --- /dev/null +++ b/MyAndroid/app/src/main/res/drawable/ic_search.xml @@ -0,0 +1,10 @@ + + + diff --git a/MyAndroid/app/src/main/res/layout/activity_main.xml b/MyAndroid/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..c928bb7 --- /dev/null +++ b/MyAndroid/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/MyAndroid/app/src/main/res/layout/detail_fragment.xml b/MyAndroid/app/src/main/res/layout/detail_fragment.xml new file mode 100644 index 0000000..4a1f2d9 --- /dev/null +++ b/MyAndroid/app/src/main/res/layout/detail_fragment.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MyAndroid/app/src/main/res/layout/fragment_galery.xml b/MyAndroid/app/src/main/res/layout/fragment_galery.xml new file mode 100644 index 0000000..356e36c --- /dev/null +++ b/MyAndroid/app/src/main/res/layout/fragment_galery.xml @@ -0,0 +1,52 @@ + + + + + + + + + +