Skip to content

furkanbalci0/TravelGuide

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

32 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Travel Guide Mobile Application

This mobile application is a guide application. Users who want to have information about places to visit can benefit from this application.

  • You can explore new places in it.
  • You can read detailed articles about the places you have discovered.
  • You can like discovered places or save to remember them later.
  • You can make new searches and get information about the results.
  • You can browse pictures of all places by clicking on them.

Details

  • All classes are isolated.
  • 2 APIs were used in the whole project.
  • Room database is used.
  • API key and endpoint addresses are hidden.
  • DependencyInject has been used literally.
  • I used Resource in Flow.
  • I used @string.xml, @dimen.xml, @colors.xml.

πŸ—œοΈ Technologies

  • Okhttp
  • Retrofit
  • Kotlin Coroutines
  • ViewModel
  • Glide
  • Dagger & Hilt
  • Room
  • DataBinding
  • Material Design

πŸ’Ύ Clean Architecture (MVVM)

image

πŸ–ΌοΈ Outputs

🏠 Home

  • Attention has been paid to the distinction between Fragment & ViewModel.
  • Observe operations are done in the fragment.
private fun initializeDeals() {

        //Observer deals.
        homeViewModel.attractionsLiveData.observe(viewLifecycleOwner) {
            binding.dealsRecyclerview.adapter = HomeDealsAdapter(it)
        }

        //Observe loading.
        homeViewModel.loading.observe(viewLifecycleOwner) {
            if (it) {
                binding.dealsRecyclerview.visibility = View.GONE
                binding.dealsErrorText.visibility = View.GONE
                binding.dealsProgressBar.visibility = View.VISIBLE
            } else {
                binding.dealsRecyclerview.visibility = View.VISIBLE
                binding.dealsErrorText.visibility = View.GONE
                binding.dealsProgressBar.visibility = View.GONE
            }
        }

        //Observe error.
        homeViewModel.error.observe(viewLifecycleOwner) {
            if (it) {
                binding.dealsRecyclerview.visibility = View.GONE
                binding.dealsErrorText.visibility = View.VISIBLE
            } else {
                binding.dealsRecyclerview.visibility = View.VISIBLE
                binding.dealsErrorText.visibility = View.GONE
            }
        }
    }
Image Comment
β€’ All buttons are static.
β€’ The clicked button updates the tab layout.
β€’ Only cars button gives "In Care" error.
β€’ The incoming error message can be changed from the string.xml file.
β€’ When the button is clicked, SoundEffectConstants.CLICK sound is heard.
β€’ TabLayout is used and texts are defined as static.
β€’ RecyclerView contents are updated when TabItem is clicked.
β€’ Without freezing the UI, all processes are running in the background thanks to Coroutine.
β€’ It uses custom progress bar while loading all images.
β€’ All images are clickable.
β€’ Clicked items move slightly upwards.
β€’ The picture and the background are separate from each other.
β€’ It can be scrolled up or down depending on the screen size.
β€’ When the keyboard is opened, it is prevented from moving to the top.
β€’ It doesn't work in DetailFragment.

image

πŸ” Search

  • Updates can be made by searching for Region, Country, Venue, etc. in this screen.
  • When Destinations is scrolled, new items will start loading.
  • SearchView will transfer SearchResultFragment when any text is written and the written text will be transferred there.

Note: Example function in view model.

fun addBookmark(
        attraction: Attraction,
        onBookmarkAddButtonClick: (Attraction) -> Unit
    ) {
        viewModelScope.launch {
            dbRepository.insert(attraction).collect() {
                when (it) {

                    is Resource.Loading -> {
                        loading.postValue(true)
                        error.postValue(false)
                    }

                    is Resource.Error -> {
                        loading.postValue(false)
                        error.postValue(true)
                    }

                    is Resource.Success -> {
                        loading.postValue(false)
                        error.postValue(false)
                        bookmarkList.add(attraction.id)
                        onBookmarkAddButtonClick(attraction)
                    }
                }
            }
        }
    }
Image Comment
β€’ A completely custom edit text has been created.
β€’ As soon as any button is clicked, SearchResultFragment will be transferred and the first letter in it will be transferred to the new fragment with arguments.
β€’ When clicked, it will redirect to a detail page showing information about that region.
β€’ It lists the important places of the countries thanks to TriposoAPI.
β€’ All items start loading when we swipe right.
β€’ The Attraction list of the last selected country is sent to the Adapter.
β€’ When the Bookmark button is clicked, the Room database is recorded and controlled.
β€’ When clicked, it sends an informational message.

image

🧳 Trip Plan & Bookmarks

  • You can add the places you want to travel and choose your round trip days.
  • The Attractions you have registered are listed in the Bookmark section.
Image Comment
β€’ Static tab layout. (Trips and Bookmarks)
β€’ When clicked, the recycler view adapter is updated.
β€’ Clicking the FloatActionButton opens a new BottomSheets. The data clicked on this pop-up screen is recorded in SharedPreferences and when Add Trip button is clicked, Room is recorded via view model.
β€’ The Attraction classes that have been bookmarked in other fragments are listed here.
β€’ When clicked, it redirects to the detail page.

image

⚜️ Guide

  • You can get historical information about countries and read blog posts.
  • You can select the country you want to get information from in the TabLayout section.
Image Comment
β€’ It lists the important places of the countries thanks to TriposoAPI.
β€’ All items start loading when we swipe right.
β€’ A completely custom edit text has been created.
β€’ As soon as any button is clicked, SearchResultFragment will be transferred and the first letter in it will be transferred to the new fragment with arguments.
β€’ When clicked, it will redirect to a detail page showing information about that region.
β€’ A list of countries is drawn by TriposoApi.
β€’ Article is listed related to the clicked country.
β€’ When the heart button is clicked, it saves it into SharedPreferences.
β€’ UI(main) thread is not affected by the processes.

image

πŸ”₯ Search Results

  • You can get historical information about countries and read blog posts.
  • You can select the country you want to get information from in the TabLayout section.
Image Comment
β€’ When you want to search for a country or region, you need to type in the SearchView section.
β€’ The transition to this screen will be very 'smooth'.
β€’ Results related to the searched word will be listed.
β€’ It does not send continuous requests for the searched word and sends a request 1.5 seconds after the word is typed.
β€’ Click the 'Bookmark Button' for the 'Attraction' you want to save.

image

πŸ“‡ Detail

  • Shows the classes Article, Attraction, Country, Destination, MockObject and Trip in it. For this, I created an interface named DetailObject as Dependecy Revision and implemented it to all classes.
  • We send the implemented class with DataBinding.
<data>
    <variable
        name="detailObject"
        type="com.furkanbalci.travelguide.di.DetailObject" />
</data>
Image Comment
β€’ It places the DetailObject class that is sent into it with DataBinding where necessary. Room Database can be saved.
β€’ Selected picture can be enlarged by clicking the enlarge button.

image

πŸ’‰ Dependency Injection

I created an annotation class to return 2 Retrofit objects.

image

...
    @MockApi
    @Provides
    @Singleton
    fun provideMockService(@MockApi retrofit: Retrofit): MockApiService {
        return retrofit.create(MockApiService::class.java)
    }

    @TriposoApi
    @Provides
    @Singleton
    fun provideTriposoService(@TriposoApi retrofit: Retrofit): TriposoApiService {
        return retrofit.create(TriposoApiService::class.java)
    }

    @Qualifier
    @Retention(AnnotationRetention.BINARY)
    annotation class MockApi

    @Qualifier
    @Retention(AnnotationRetention.BINARY)
    annotation class TriposoApi

image

⛓️ Obfuscation

image image

About

This is my graduation project for FMSS. It is a travel application that lists and records places to visit.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages