diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 526b4c2..a2d7c21 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -13,7 +13,6 @@ - diff --git a/.idea/misc.xml b/.idea/misc.xml index 3636ffa..ff7ed65 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,17 +3,64 @@ diff --git a/README.md b/README.md new file mode 100644 index 0000000..7fcfc6a --- /dev/null +++ b/README.md @@ -0,0 +1,33 @@ +# Inquire +Inquire is a question and answer application for professional and enthusiast programmers. +user can post in image formate with description. +Inquire is a code sharing and dicovery platform aimed at improving developer prductivity. + +## Getting Started +- Fork this repo and run the `git clone ` command from your terminal/bash +- gradle sync + + +## Technical Jargon +- Android SDK API 31 +- XML View System with Material Design 3 +- Kotlin 1.6.10 +- Kotlin Coroutines and Flow for concurrency and async +- Clean MVVM Architecture with Repository pattern +- Room ORM with SQLite for Database Caching +- Retrofit and Moshi for network calls +- Dependency Injection using Hilt +- Firebase Storage for image upload +- Android CodeView by kbiakov to render code snippets +- Coil for image loading +- ImagePicker by dhaval2404 +- AndroidVeil by SkyDoves for the shimmer effect +- Google's Modern Storage library for Storage interactions +- Konfetti by dionsegijn for showing confettin on publishing first snippet +- Lottie by Airbnb for graphic animations +- HtTextView for text Animations + + + + +M diff --git a/app/build.gradle b/app/build.gradle index d37ce93..d17ead6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,6 +2,8 @@ plugins { id 'com.android.application' id 'org.jetbrains.kotlin.android' id 'com.google.gms.google-services' + id 'kotlin-kapt' + id("androidx.navigation.safeargs") } android { @@ -33,15 +35,28 @@ android { buildFeatures { viewBinding true } + + buildscript { + repositories { + mavenCentral() + } + } + } dependencies { implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.appcompat:appcompat:1.4.1' - implementation 'com.google.android.material:material:1.5.0' + implementation 'com.google.android.material:material:1.7.0-alpha01' implementation 'androidx.constraintlayout:constraintlayout:2.1.3' implementation 'com.google.firebase:firebase-auth-ktx' + implementation 'androidx.navigation:navigation-fragment-ktx:2.4.2' + implementation 'androidx.navigation:navigation-ui-ktx:2.4.1' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' + implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.1' + implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1' + implementation 'androidx.room:room-common:2.4.2' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' @@ -50,6 +65,37 @@ dependencies { implementation platform('com.google.firebase:firebase-bom:29.2.0') implementation 'com.firebaseui:firebase-ui-auth:8.0.0' implementation 'com.google.firebase:firebase-analytics' + //firebase firestore dependencies + implementation 'com.google.firebase:firebase-firestore-ktx' +// DI + implementation "com.google.dagger:hilt-android:2.38.1" + kapt "com.google.dagger:hilt-compiler:2.38.1" + // Image handling + implementation "io.coil-kt:coil:1.4.0" + implementation 'com.github.dhaval2404:imagepicker:2.1' +//code view + implementation 'com.github.kbiakov:CodeView-Android:1.3.2' + // Storage + implementation("com.squareup.okio:okio:3.0.0") + implementation("com.google.modernstorage:modernstorage-permissions:1.0.0-alpha06") + implementation("com.google.modernstorage:modernstorage-storage:1.0.0-alpha06") + + // Buttons with Shine Effect for Bookmarking + implementation 'com.github.varunest:sparkbutton:1.0.6' + implementation 'nl.dionsegijn:konfetti-xml:2.0.2' + //firbase storage + implementation 'com.google.firebase:firebase-storage-ktx:20.0.1' + + implementation 'com.firebaseui:firebase-ui-firestore:7.2.0' + //glide + implementation 'com.github.bumptech.glide:glide:4.13.0' + annotationProcessor 'com.github.bumptech.glide:compiler:4.13.0' + implementation "android.arch.lifecycle:runtime:1.1.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" + + + + } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ca727e3..5893a46 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,8 @@ + + + + + @@ -31,7 +42,7 @@ () + val error = MutableLiveData() + + + + + fun saveUser(){ + var id = "" + var name = "" + var photoUrl = "" + var email = "" + val bio = "" + val username = "" + val githubUsername = "" + Firebase.auth.currentUser?.let { + id = it.uid + name = it.displayName ?: "" + photoUrl = it.photoUrl?.toString() ?: "" + email = it.email ?: "" + } + + val user = User(username, name, photoUrl, email, bio, githubUsername) + Firebase + .firestore + .collection("users") + .document(id) + .set(user) + .addOnSuccessListener { + Log.d(TAG, "saveUser successful") + success.value = true + } + .addOnFailureListener { + Log.d(TAG, "saveUser failed") + error.value = it.message + } + + + + + + + } +} \ No newline at end of file diff --git a/app/src/main/java/dev/aman/inquire/individual/data/UserViewModel.kt b/app/src/main/java/dev/aman/inquire/individual/data/UserViewModel.kt new file mode 100644 index 0000000..4c064da --- /dev/null +++ b/app/src/main/java/dev/aman/inquire/individual/data/UserViewModel.kt @@ -0,0 +1,30 @@ +package dev.aman.inquire.individual.data + +import androidx.lifecycle.ViewModel +import com.firebase.ui.auth.data.model.User +import com.google.android.gms.tasks.Task +import com.google.firebase.auth.FirebaseUser +import com.google.firebase.auth.ktx.auth +import com.google.firebase.firestore.DocumentSnapshot +import com.google.firebase.firestore.FirebaseFirestore +import com.google.firebase.ktx.Firebase +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch + +class UserViewModel: ViewModel() { + private val db = FirebaseFirestore.getInstance() + private val userCollection = db.collection("users") + private val user: FirebaseUser = Firebase.auth.currentUser!! + fun addUser(user: User?) { + user?.let { + GlobalScope.launch(Dispatchers.IO) { + userCollection.document().set(it) + } + } + } + fun getUserById(uId: String) : Task { + return userCollection.document(uId).get() + } + +} \ No newline at end of file diff --git a/app/src/main/java/dev/aman/inquire/individual/data/model/Inquire.kt b/app/src/main/java/dev/aman/inquire/individual/data/model/Inquire.kt new file mode 100644 index 0000000..49dff07 --- /dev/null +++ b/app/src/main/java/dev/aman/inquire/individual/data/model/Inquire.kt @@ -0,0 +1,26 @@ +package dev.aman.inquire.individual.data.model + + +import androidx.room.PrimaryKey +import com.google.android.gms.tasks.Task +import com.google.firebase.firestore.DocumentSnapshot +import com.google.firebase.firestore.Exclude +import com.google.firebase.firestore.IgnoreExtraProperties +import dev.aman.inquire.utils.InquireState +import java.util.* + +@IgnoreExtraProperties +data class Inquire( + @Exclude @get: Exclude var id:String = "", + var title: String = "", + val description: String = "", + val inquire_code: String = "", + val language: String = "", + val createdBY: String ="", + val imageUri: String? = null, + var status: InquireState = InquireState.UnBookmarked, + var UpVotes: Int = 0, + var createdAt:Long=0L, + var userImage:String?=null + + ) \ No newline at end of file diff --git a/app/src/main/java/dev/aman/inquire/individual/data/model/User.kt b/app/src/main/java/dev/aman/inquire/individual/data/model/User.kt new file mode 100644 index 0000000..0c44068 --- /dev/null +++ b/app/src/main/java/dev/aman/inquire/individual/data/model/User.kt @@ -0,0 +1,15 @@ +package dev.aman.inquire.individual.data.model + +import android.net.Uri + +data class User( + val username: String = "", + val name: String = "", + val photo: String = "", + val email: String = "", + val bio: String = "", + + val github_username: String = "", + + + ) \ No newline at end of file diff --git a/app/src/main/java/dev/aman/inquire/individual/ui/create/CreateFragment.kt b/app/src/main/java/dev/aman/inquire/individual/ui/create/CreateFragment.kt new file mode 100644 index 0000000..bb6d942 --- /dev/null +++ b/app/src/main/java/dev/aman/inquire/individual/ui/create/CreateFragment.kt @@ -0,0 +1,54 @@ +package dev.aman.inquire.individual.ui.create + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import androidx.viewpager2.adapter.FragmentStateAdapter +import dev.aman.inquire.databinding.FragmentCreateBinding +import dev.aman.inquire.individual.ui.create.form.AddCodeFragment +import dev.aman.inquire.individual.ui.create.form.AddDetailsFragment +import dev.aman.inquire.individual.ui.create.form.AddImageFragment +import dev.aman.inquire.utils.DepthPageTransformer + + +class CreateFragment : Fragment() { + private lateinit var binding: FragmentCreateBinding + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + // Inflate the layout for this fragment + binding = FragmentCreateBinding.inflate(inflater, container, false) + return binding.root + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.formPager.adapter = ScreenSlidePagerAdapter(this) + binding.formPager.isUserInputEnabled = false + binding.formPager.setPageTransformer(DepthPageTransformer()) + } + + + fun nextPage() { + binding.formPager.currentItem = binding.formPager.currentItem + 1 + } + private class ScreenSlidePagerAdapter(fa: Fragment) : FragmentStateAdapter(fa) { + override fun getItemCount(): Int = 3 + + override fun createFragment(position: Int): Fragment = when (position) { + 0 -> AddDetailsFragment() + 1 -> AddImageFragment() + 2 -> AddCodeFragment() + else -> { + throw IllegalArgumentException("Invalid position") + } + } + } +} + + + diff --git a/app/src/main/java/dev/aman/inquire/individual/ui/create/InputCodeDialogFragment.kt b/app/src/main/java/dev/aman/inquire/individual/ui/create/InputCodeDialogFragment.kt new file mode 100644 index 0000000..fcc0d84 --- /dev/null +++ b/app/src/main/java/dev/aman/inquire/individual/ui/create/InputCodeDialogFragment.kt @@ -0,0 +1,50 @@ +package dev.aman.inquire.individual.ui.create + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.setFragmentResult +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import dev.aman.inquire.databinding.FragmentInputCodeDialogBinding +import dev.aman.inquire.utils.Constants + + +class InputCodeDialogFragment : BottomSheetDialogFragment(){ + + private lateinit var binding: FragmentInputCodeDialogBinding + + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + // Inflate the layout for this fragment + binding = FragmentInputCodeDialogBinding.inflate(inflater, container, false) + return binding.root + + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + binding.buttonDone.setOnClickListener { + if (binding.textFieldInputCode.editText?.text.isNullOrEmpty()) { + binding.textFieldInputCode.error = "Code cannot be empty" + } else { + setFragmentResult(Constants.KEY_INPUT_CODE_DIALOG, Bundle().apply { + putString( + Constants.KEY_CODE, + binding.textFieldInputCode.editText?.text.toString() + ) + }) + dismiss() + } + + binding.buttonCancel.setOnClickListener { + dismiss() + } + } + + + } +} \ No newline at end of file diff --git a/app/src/main/java/dev/aman/inquire/individual/ui/create/form/AddCodeFragment.kt b/app/src/main/java/dev/aman/inquire/individual/ui/create/form/AddCodeFragment.kt new file mode 100644 index 0000000..0237395 --- /dev/null +++ b/app/src/main/java/dev/aman/inquire/individual/ui/create/form/AddCodeFragment.kt @@ -0,0 +1,128 @@ +package dev.aman.inquire.individual.ui.create.form + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.activity.result.contract.ActivityResultContracts +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.fragment.app.setFragmentResultListener +import androidx.lifecycle.lifecycleScope +import androidx.navigation.fragment.findNavController +import com.google.modernstorage.permissions.RequestAccess +import com.google.modernstorage.permissions.StoragePermissions +import com.google.modernstorage.storage.AndroidFileSystem +import com.google.modernstorage.storage.toOkioPath +import dev.aman.inquire.databinding.FragmentAddCodeBinding +import dev.aman.inquire.individual.data.InquireViewModel +import dev.aman.inquire.individual.ui.create.InputCodeDialogFragment +import dev.aman.inquire.utils.Constants +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import nl.dionsegijn.konfetti.core.Party +import nl.dionsegijn.konfetti.core.emitter.Emitter + + +import okio.buffer +import java.util.concurrent.TimeUnit + + +class AddCodeFragment : Fragment() { + +private lateinit var binding:FragmentAddCodeBinding + private val model by activityViewModels() + private lateinit var fileSystem: AndroidFileSystem + + private val requestFile = + registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri -> + if (uri != null) { + model.inquire_code = fileSystem.source(uri.toOkioPath()).buffer().readUtf8().also { + binding.codeViewSnippetCode.apply { + + setCode(it) + } + } + } + } + + private val requestStorageAccess = registerForActivityResult(RequestAccess()) { hasAccess -> + if (!hasAccess) { + requestFile.launch(arrayOf("text/*")) + } + } + + + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + // Inflate the layout for this fragment + binding= FragmentAddCodeBinding.inflate(inflater,container,false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + // auto language recognition + fileSystem = AndroidFileSystem(requireContext()) + setFragmentResultListener(Constants.KEY_INPUT_CODE_DIALOG) { _, bundle -> + val code = bundle.getString(Constants.KEY_CODE) + if (code != null) { + model.inquire_code = code + } + binding.codeViewSnippetCode.apply { + + + if (code != null) { + setCode(code) + } + + + } + } + + + binding.buttonInputCode.setOnClickListener { + InputCodeDialogFragment().show(parentFragmentManager, "INPUT_MODAL") + + } + binding.buttonSelectFileFromDevice.setOnClickListener{ + requestStorageAccess.launch( + RequestAccess.Args( + action = StoragePermissions.Action.READ, + types = listOf(StoragePermissions.FileType.Document), + createdBy = StoragePermissions.CreatedBy.AllApps + ) + ) + } + binding.publishButton.setOnClickListener { + if(model.inquire_code.isNotEmpty()) { + + + model.publishInquire() + binding.konfetti.start( + Party( + emitter = Emitter(duration = 3, TimeUnit.SECONDS).perSecond( + 30 + ) + ) + ) + lifecycleScope.launch { + delay(3000) + findNavController().popBackStack() + } + + + } + + + } + } + + + + } + + diff --git a/app/src/main/java/dev/aman/inquire/individual/ui/create/form/AddDetailsFragment.kt b/app/src/main/java/dev/aman/inquire/individual/ui/create/form/AddDetailsFragment.kt new file mode 100644 index 0000000..20f1182 --- /dev/null +++ b/app/src/main/java/dev/aman/inquire/individual/ui/create/form/AddDetailsFragment.kt @@ -0,0 +1,80 @@ +package dev.aman.inquire.individual.ui.create.form + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup + +import android.widget.Toast +import androidx.core.widget.doOnTextChanged +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import dev.aman.inquire.databinding.FragmentAddDetailsBinding +import dev.aman.inquire.individual.data.InquireViewModel +import dev.aman.inquire.individual.ui.create.CreateFragment + + +class AddDetailsFragment : Fragment() { + private lateinit var binding: FragmentAddDetailsBinding + private val model by activityViewModels() + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = FragmentAddDetailsBinding.inflate(inflater, container, false) + return binding.root + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + loadView() + + } + + private fun loadView() { + binding.textFieldSnippetTitle.editText?.doOnTextChanged { text, _, _, _ -> + binding.textFieldSnippetTitle.error = if (text.isNullOrBlank()) { + "Title is required" + } else { + null + } + model.title= text.toString() + + } + + binding.textFieldSnippetDescription.editText?.doOnTextChanged { text, _, _, _ -> + binding.textFieldSnippetDescription.error = if (text.isNullOrBlank()) { + "Description is required" + } else { + null + } + model.description= text.toString() + + } + + + binding.textFieldSnippetTags.editText?.doOnTextChanged { text, _, _, _ -> + binding.textFieldSnippetTags.error = if (text.isNullOrBlank()) { + "Language are required" + } else { + null + } + model.language= text.toString() + } + + + + + binding.addDetailsButtonNext.setOnClickListener{ + if (binding.textFieldSnippetTitle.editText?.text.isNullOrBlank() || + binding.textFieldSnippetDescription.editText?.text.isNullOrBlank() || + binding.textFieldSnippetTags.editText?.text.isNullOrBlank() + ){ + Toast.makeText(context,"Please fill all the fields",Toast.LENGTH_SHORT).show() + }else{ + (parentFragment as? CreateFragment)?.nextPage() + + } + } + } +} + diff --git a/app/src/main/java/dev/aman/inquire/individual/ui/create/form/AddImageFragment.kt b/app/src/main/java/dev/aman/inquire/individual/ui/create/form/AddImageFragment.kt new file mode 100644 index 0000000..d96a2e3 --- /dev/null +++ b/app/src/main/java/dev/aman/inquire/individual/ui/create/form/AddImageFragment.kt @@ -0,0 +1,117 @@ +package dev.aman.inquire.individual.ui.create.form + +import android.app.Activity +import android.content.Intent +import android.os.Build.VERSION_CODES.P +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.activity.result.contract.ActivityResultContracts +import androidx.fragment.app.activityViewModels +import com.github.dhaval2404.imagepicker.ImagePicker +import com.github.dhaval2404.imagepicker.ImagePicker.Companion.REQUEST_CODE +import com.google.firebase.ktx.Firebase +import com.google.firebase.storage.ktx.storage +import dev.aman.inquire.databinding.FragmentAddImageBinding +import dev.aman.inquire.individual.data.InquireViewModel +import dev.aman.inquire.individual.ui.create.CreateFragment +import java.util.* + + +class AddImageFragment : Fragment() { + private lateinit var binding: FragmentAddImageBinding + val fileName = UUID.randomUUID().toString() +".jpg" + val refStorage = Firebase.storage.reference.child("images/$fileName") + + private val model by activityViewModels() + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + // Inflate the layout for this fragment + binding = FragmentAddImageBinding.inflate(inflater, container, false) + return binding.root + } + + private val startForImageResult = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + val resultCode = result.resultCode + val data = result.data + if (resultCode == Activity.RESULT_OK) { + + val imageUri=data?.data + + val uploadTask = refStorage.putFile(imageUri!!) + try { + val url = uploadTask.continueWithTask { task -> + if (!task.isSuccessful) { + task.exception?.let { + throw it + } + } + refStorage.downloadUrl + }.addOnCompleteListener { + if (it.isSuccessful) { + val publicDownloadUrl = it.result + // Here we have the URL + model.imageUri= publicDownloadUrl.toString() + + } + } + } catch (e: Exception) { + e.printStackTrace() + } + + binding.imageViewResult.setImageURI(imageUri) + Toast.makeText(context, "Image Selected", Toast.LENGTH_SHORT).show() + if (resultCode == Activity.RESULT_CANCELED) { + // User cancelled the image capture + Toast.makeText(context, "User cancelled the image capture", Toast.LENGTH_SHORT) + .show() + + } + } + } + + + + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + binding.imageViewPickCamera.setOnClickListener { + ImagePicker.with(this@AddImageFragment) + .cameraOnly() + .crop() + .compress(1024) + .maxResultSize(1080, 1080) + .createIntent { startForImageResult.launch(it) } + } + + binding.imageViewPickGallery.setOnClickListener { + ImagePicker.with(this@AddImageFragment) + .galleryOnly() + .crop() + .compress(1024) + .maxResultSize(1080, 1080) + .createIntent { startForImageResult.launch(it) } + } + + binding.buttonNext.setOnClickListener { + (parentFragment as CreateFragment).nextPage() + } + binding.videoPicker.setOnClickListener{ + val intent = Intent() + intent.type = "video/*" + intent.action = Intent.ACTION_PICK + startActivityForResult(Intent.createChooser(intent, "Select Video"),REQUEST_CODE) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/dev/aman/inquire/individual/ui/home/HomeFragment.kt b/app/src/main/java/dev/aman/inquire/individual/ui/home/HomeFragment.kt new file mode 100644 index 0000000..1a65ef5 --- /dev/null +++ b/app/src/main/java/dev/aman/inquire/individual/ui/home/HomeFragment.kt @@ -0,0 +1,39 @@ +package dev.aman.inquire.individual.ui.home + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.google.android.material.tabs.TabLayoutMediator +import dev.aman.inquire.databinding.FragmentHomeBinding + + +class HomeFragment : Fragment() { + private lateinit var binding: FragmentHomeBinding + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + // Inflate the layout for this fragment + binding = FragmentHomeBinding.inflate(inflater, container, false) + return binding.root + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + renderContent() + } + + private fun renderContent() { + binding.viewpager2TasksFragments.adapter = HomeFragmentAdapter(this) + TabLayoutMediator(binding.tabLayout, binding.viewpager2TasksFragments) { tab, position -> + tab.text = when (position) { + 0 -> "Feeds" + + 1->"Bookmarked" + + else -> "Others" + } + }.attach() + } +} diff --git a/app/src/main/java/dev/aman/inquire/individual/ui/home/HomeFragmentAdapter.kt b/app/src/main/java/dev/aman/inquire/individual/ui/home/HomeFragmentAdapter.kt new file mode 100644 index 0000000..d4deed5 --- /dev/null +++ b/app/src/main/java/dev/aman/inquire/individual/ui/home/HomeFragmentAdapter.kt @@ -0,0 +1,18 @@ +package dev.aman.inquire.individual.ui.home + +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter +import dev.aman.inquire.individual.ui.home.bookmarked.BookMarkedFragment +import dev.aman.inquire.individual.ui.home.feeds.FeedsFragment + +class HomeFragmentAdapter(fragment: Fragment): FragmentStateAdapter(fragment){ + override fun getItemCount() = 1 + override fun createFragment(position: Int): Fragment { + return when (position) { + 0 -> FeedsFragment() + 1-> BookMarkedFragment() + else -> FeedsFragment() + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/dev/aman/inquire/individual/ui/home/bookmarked/BookMarkedFragment.kt b/app/src/main/java/dev/aman/inquire/individual/ui/home/bookmarked/BookMarkedFragment.kt new file mode 100644 index 0000000..f1cce85 --- /dev/null +++ b/app/src/main/java/dev/aman/inquire/individual/ui/home/bookmarked/BookMarkedFragment.kt @@ -0,0 +1,24 @@ +package dev.aman.inquire.individual.ui.home.bookmarked + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import dev.aman.inquire.R + + +class BookMarkedFragment : Fragment() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.fragment_book_marked, container, false) + } + +} \ No newline at end of file diff --git a/app/src/main/java/dev/aman/inquire/individual/ui/home/description/ExpandedImageActivity.kt b/app/src/main/java/dev/aman/inquire/individual/ui/home/description/ExpandedImageActivity.kt new file mode 100644 index 0000000..a4122ed --- /dev/null +++ b/app/src/main/java/dev/aman/inquire/individual/ui/home/description/ExpandedImageActivity.kt @@ -0,0 +1,12 @@ +package dev.aman.inquire.individual.ui.home.description + +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import dev.aman.inquire.R + +class ExpandedImageActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_expanded_image) + } +} \ No newline at end of file diff --git a/app/src/main/java/dev/aman/inquire/individual/ui/home/description/FeedsDescriptionFragment.kt b/app/src/main/java/dev/aman/inquire/individual/ui/home/description/FeedsDescriptionFragment.kt new file mode 100644 index 0000000..40a562d --- /dev/null +++ b/app/src/main/java/dev/aman/inquire/individual/ui/home/description/FeedsDescriptionFragment.kt @@ -0,0 +1,93 @@ +package dev.aman.inquire.individual.ui.home.description + +import android.app.Dialog +import android.os.Bundle +import android.util.Log +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.os.bundleOf +import androidx.navigation.fragment.findNavController +import androidx.navigation.fragment.navArgs + +import coil.load +import coil.transform.RoundedCornersTransformation + +import com.google.android.material.bottomsheet.BottomSheetBehavior +import com.google.android.material.bottomsheet.BottomSheetDialog +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import com.google.firebase.firestore.ktx.firestore + +import com.google.firebase.ktx.Firebase +import dev.aman.inquire.R + +import dev.aman.inquire.databinding.FragmentFeedsDescriptionBinding +import io.github.kbiakov.codeview.adapters.Options +import io.github.kbiakov.codeview.highlight.ColorTheme + +class FeedsDescriptionFragment : BottomSheetDialogFragment() { + private lateinit var binding: FragmentFeedsDescriptionBinding + lateinit var imageUri:String + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentFeedsDescriptionBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return (super.onCreateDialog(savedInstanceState) as BottomSheetDialog).apply { + setOnShowListener { + behavior.state = BottomSheetBehavior.STATE_EXPANDED + } + } + } + + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + val args: FeedsDescriptionFragmentArgs by navArgs() + var id = args.inquireId + Firebase.firestore.collection("posts").document(id).get().addOnSuccessListener { + + Log.d("TAG", it.data.toString()) + if (it.data != null) { + Log.d("Firestore", it.data.toString()) + binding.textViewSnippetDescription.text = it.data!!["description"].toString() + binding.textViewSnippetTitle.text = it.data!!["title"].toString() + binding.languageChip.text = it.data!!["language"].toString() + imageUri=it.data!!["image"].toString() + binding.imageViewInquire.load(it.data!!["imageUri"].toString()){ + error(R.mipmap.ic_launcher) + crossfade(true) + transformations(RoundedCornersTransformation(20f)) + + + } + + binding.codeViewSnippetCode.apply{ + val code =it.data!!["inquire_code"].toString() + setOptions(Options.Default.get(requireContext()).withTheme(ColorTheme.MONOKAI)) + setCode(code ?: "An error occurred while loading the code!") + } + binding.buttonCopyCode.setOnClickListener{ + + + } + + + + } + + + } + + + } +} \ No newline at end of file diff --git a/app/src/main/java/dev/aman/inquire/individual/ui/home/feeds/FeedsAdapter.kt b/app/src/main/java/dev/aman/inquire/individual/ui/home/feeds/FeedsAdapter.kt new file mode 100644 index 0000000..8d52b4b --- /dev/null +++ b/app/src/main/java/dev/aman/inquire/individual/ui/home/feeds/FeedsAdapter.kt @@ -0,0 +1,80 @@ +package dev.aman.inquire.individual.ui.home.feeds + +import android.content.ClipData +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.navigation.findNavController +import androidx.recyclerview.widget.RecyclerView +import coil.load +import coil.transform.RoundedCornersTransformation +import com.bumptech.glide.Glide +import com.bumptech.glide.load.resource.bitmap.TransformationUtils.circleCrop +import dev.aman.inquire.R +import dev.aman.inquire.databinding.ItemPostBinding +import dev.aman.inquire.individual.data.model.Inquire +import dev.aman.inquire.individual.ui.home.HomeFragment +import dev.aman.inquire.individual.ui.home.HomeFragmentDirections +import dev.aman.inquire.utils.Utils + +class FeedsAdapter(private val inquireList:ArrayList):RecyclerView.Adapter() { + class FeedsViewHolder(val binding:ItemPostBinding) : RecyclerView.ViewHolder(binding.root) { + fun bind(inquire: Inquire){ + with(binding){ + inquireTitle.text=inquire.title + inquireDescription.text=inquire.description + languageChip.text=inquire.language + userName.text=inquire.createdBY + timeStamp.text=Utils.getTimeAgo(inquire.createdAt) + imageView.load(inquire.userImage) { + crossfade(true) + placeholder(R.drawable.usericon) + transformations(RoundedCornersTransformation(20f)) + + } + + inquireImage.load(inquire.imageUri){ + error(R.mipmap.ic_launcher) + crossfade(true) + transformations(RoundedCornersTransformation(20f)) + } + root.setOnClickListener{ + val action= HomeFragmentDirections.actionHomeFragmentToFeedsDescriptionFragment( + inquire.id + ) + it.findNavController().navigate(action) + } + + } + + } + + + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FeedsViewHolder { + return FeedsViewHolder( + ItemPostBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + ) + + } + + override fun getItemCount(): Int { + return inquireList.size + } + + override fun onBindViewHolder(holder: FeedsAdapter.FeedsViewHolder, position: Int) { + val inquire = inquireList[position] + holder.bind(inquireList[position]) + /*Glide.with(this).load(model.photo).circleCrop().into(binding.imageViewUserImage)*/ + + + + } +} \ No newline at end of file diff --git a/app/src/main/java/dev/aman/inquire/individual/ui/home/feeds/FeedsFragment.kt b/app/src/main/java/dev/aman/inquire/individual/ui/home/feeds/FeedsFragment.kt new file mode 100644 index 0000000..12698a7 --- /dev/null +++ b/app/src/main/java/dev/aman/inquire/individual/ui/home/feeds/FeedsFragment.kt @@ -0,0 +1,76 @@ +package dev.aman.inquire.individual.ui.home.feeds + +import android.os.Bundle +import android.util.Log +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.google.firebase.firestore.* +import dev.aman.inquire.databinding.FragmentFeedsBinding +import dev.aman.inquire.individual.data.model.Inquire + +class FeedsFragment : Fragment() { + private lateinit var binding: FragmentFeedsBinding + private lateinit var mAdapter: FeedsAdapter + private lateinit var recyclerView: RecyclerView + private lateinit var inquireList:ArrayList + private lateinit var db:FirebaseFirestore + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + // Inflate the layout for this fragment + binding= FragmentFeedsBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + recyclerView=binding.feedsRecylerViewer + recyclerView.layoutManager=LinearLayoutManager(context) + recyclerView.setHasFixedSize(true) + inquireList=ArrayList() + mAdapter= FeedsAdapter(inquireList) + recyclerView.adapter=mAdapter + EvenChangeList() + + + } + + private fun EvenChangeList() { + db = FirebaseFirestore.getInstance() + db.collection("posts").addSnapshotListener { value, error -> + + + if(error!=null){ + Log.e("firebase error",error.message.toString()) + return@addSnapshotListener + } + for(dc:DocumentChange in value!!.documentChanges){ + if(dc.type== DocumentChange.Type.ADDED){ + val inquire=dc.document.toObject(Inquire::class.java) + inquire.id=dc.document.id + inquireList.add(inquire) + mAdapter.notifyDataSetChanged() + } + } + } + } + + + + + + + + +} + + + + + + diff --git a/app/src/main/java/dev/aman/inquire/individual/login/IndividualLoginActivity.kt b/app/src/main/java/dev/aman/inquire/individual/ui/login/IndividualLoginActivity.kt similarity index 51% rename from app/src/main/java/dev/aman/inquire/individual/login/IndividualLoginActivity.kt rename to app/src/main/java/dev/aman/inquire/individual/ui/login/IndividualLoginActivity.kt index d1720cd..4c1dc72 100644 --- a/app/src/main/java/dev/aman/inquire/individual/login/IndividualLoginActivity.kt +++ b/app/src/main/java/dev/aman/inquire/individual/ui/login/IndividualLoginActivity.kt @@ -1,14 +1,21 @@ -package dev.aman.inquire.individual.login +package dev.aman.inquire.individual.ui.login import android.content.Intent import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.widget.Toast +import androidx.fragment.app.activityViewModels +import com.facebook.appevents.codeless.internal.ViewHierarchy.setOnClickListener import com.firebase.ui.auth.AuthUI import com.firebase.ui.auth.FirebaseAuthUIActivityResultContract import com.firebase.ui.auth.data.model.FirebaseAuthUIAuthenticationResult -import dev.aman.inquire.MainActivity +import com.google.firebase.auth.ktx.auth +import com.google.firebase.ktx.Firebase import dev.aman.inquire.databinding.ActivityLoginIndividualBinding +import dev.aman.inquire.individual.IndividualMainActivity +import dev.aman.inquire.individual.data.InquireViewModel +import dev.aman.inquire.individual.data.Repository +import dev.aman.inquire.individual.ui.profile.ProfileViewModel class IndividualLoginActivity : AppCompatActivity() { private lateinit var binding: ActivityLoginIndividualBinding @@ -16,10 +23,12 @@ class IndividualLoginActivity : AppCompatActivity() { binding= ActivityLoginIndividualBinding.inflate(layoutInflater) super.onCreate(savedInstanceState) setContentView(binding.root) - binding.signInButton.setOnClickListener{ + binding.cardViewLoginWithGoogle.setOnClickListener{ + signInLauncher.launch(signInIntent) } + } private val signInLauncher = registerForActivityResult( FirebaseAuthUIActivityResultContract() @@ -28,15 +37,40 @@ class IndividualLoginActivity : AppCompatActivity() { } private val signInIntent = AuthUI.getInstance() .createSignInIntentBuilder() - .setAvailableProviders(listOf(AuthUI.IdpConfig.GoogleBuilder().build())) + .setAvailableProviders(listOf( + + + AuthUI.IdpConfig.GoogleBuilder().build(), + + + + )) // choosing only auth for google .build() private fun onSignInResult(result: FirebaseAuthUIAuthenticationResult) { val response = result.idpResponse if (result.resultCode == RESULT_OK) { + if (Firebase.auth.currentUser != null) { + val intent = Intent(this, IndividualMainActivity::class.java) + startActivity(intent) + } + else { + Repository.error.observe(this) { + Toast.makeText(this, it, Toast.LENGTH_LONG).show() + } + Repository.success.observe(this) { + + val intent = Intent(this, IndividualMainActivity::class.java) + startActivity(intent) + } + Repository.saveUser() - val intent= Intent(this@IndividualLoginActivity, MainActivity::class.java) + } + + val intent= Intent(this@IndividualLoginActivity, IndividualMainActivity::class.java) startActivity(intent) + finish() + Repository.saveUser() } else { if (response != null) { @@ -50,4 +84,4 @@ class IndividualLoginActivity : AppCompatActivity() { } } -} \ No newline at end of file +} diff --git a/app/src/main/java/dev/aman/inquire/individual/ui/profile/AccountFragment.kt b/app/src/main/java/dev/aman/inquire/individual/ui/profile/AccountFragment.kt new file mode 100644 index 0000000..a4bd7e4 --- /dev/null +++ b/app/src/main/java/dev/aman/inquire/individual/ui/profile/AccountFragment.kt @@ -0,0 +1,72 @@ +package dev.aman.inquire.individual.ui.profile + +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.navigation.fragment.findNavController +import com.bumptech.glide.Glide +import dev.aman.inquire.R +import dev.aman.inquire.databinding.FragmentAccountBinding +import dev.aman.inquire.individual.IndividualMainActivity +import dev.aman.inquire.individual.data.InquireViewModel +import dev.aman.inquire.individual.data.model.User +import dev.aman.inquire.individual.ui.login.IndividualLoginActivity + + +class AccountFragment : Fragment() { + private lateinit var binding: FragmentAccountBinding + + private val model by activityViewModels() + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + // Inflate the layout for this fragment + + binding = FragmentAccountBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + binding.textViewUserEmail.text = model.email + binding.textViewUserName.text = model.name + Glide.with(this).load(model.photo).circleCrop().into(binding.imageViewUserImage) + /* binding.textViewUserBio.text=model.bio*/ + model.success.observe(viewLifecycleOwner) { + + if (it) { + binding.textViewUserBio.text = model.bio + binding.textViewUserName.text = model.name + binding.textViewUserEmail.text = model.email + binding.githubLink.text = model.github_Username + + + } + + } + + + + model.getData() + binding.logoutButton.setOnClickListener { + model.logout() + val intent = Intent(context, IndividualLoginActivity::class.java) + startActivity(intent) + (activity as IndividualMainActivity).finish() + + + + } + + + + + } +} + diff --git a/app/src/main/java/dev/aman/inquire/individual/ui/profile/ProfileViewModel.kt b/app/src/main/java/dev/aman/inquire/individual/ui/profile/ProfileViewModel.kt new file mode 100644 index 0000000..3782e74 --- /dev/null +++ b/app/src/main/java/dev/aman/inquire/individual/ui/profile/ProfileViewModel.kt @@ -0,0 +1,61 @@ +package dev.aman.inquire.individual.ui.profile + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.liveData +import com.firebase.ui.auth.AuthUI +import com.google.firebase.auth.FirebaseAuth +import com.google.firebase.auth.FirebaseUser +import com.google.firebase.auth.ktx.auth +import com.google.firebase.firestore.FirebaseFirestore +import com.google.firebase.firestore.ktx.firestore +import com.google.firebase.ktx.Firebase +import dev.aman.inquire.individual.data.model.User + +class ProfileViewModel:ViewModel() { + val success = MutableLiveData() + val error = MutableLiveData() + private val user: FirebaseUser = Firebase.auth.currentUser!! + private val userCollection = Firebase.firestore.collection("users") + private val auth = Firebase.auth + + private val db = FirebaseFirestore.getInstance() + private val userRef = db.collection("users") + + + var id = user.uid + var name = user.displayName ?: "" + var email = user.email ?: "" + var photo = user.photoUrl ?: "" + var bio:String? = "" + var username:String? = "" + var github_Username:String= "" + + + fun getData() { + + userRef.get() + .addOnSuccessListener { + for (document in it) { + if (document.id == id) { + username = document.data["username"].toString() + github_Username = document.data["github_username"].toString() + bio = document.data["bio"].toString() + name = document.data["name"].toString() + email = document.data["email"].toString() + photo = document.data["photo"].toString() + success.value = true + } + } + } + + } + + fun logout(){ + FirebaseAuth.getInstance().signOut() + + } +} + + + diff --git a/app/src/main/java/dev/aman/inquire/organisation/OrganisationMainActivity.kt b/app/src/main/java/dev/aman/inquire/organisation/OrganisationMainActivity.kt deleted file mode 100644 index 65ee728..0000000 --- a/app/src/main/java/dev/aman/inquire/organisation/OrganisationMainActivity.kt +++ /dev/null @@ -1,19 +0,0 @@ -package dev.aman.inquire.organisation - -import androidx.appcompat.app.AppCompatActivity -import android.os.Bundle -import android.view.LayoutInflater -import dev.aman.inquire.R -import dev.aman.inquire.databinding.ActivityOrganisationMainBinding -import dev.aman.inquire.databinding.ActivityOrganisationSplashBinding - -class OrganisationMainActivity : AppCompatActivity() { - private lateinit var binding: ActivityOrganisationMainBinding - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding= ActivityOrganisationMainBinding.inflate(layoutInflater) - setContentView(binding.root) - // orgnanisation Activity - - } -} \ No newline at end of file diff --git a/app/src/main/java/dev/aman/inquire/splashScreen/OrganisationSplashActivity.kt b/app/src/main/java/dev/aman/inquire/splashScreen/OrganisationSplashActivity.kt deleted file mode 100644 index a4e04aa..0000000 --- a/app/src/main/java/dev/aman/inquire/splashScreen/OrganisationSplashActivity.kt +++ /dev/null @@ -1,26 +0,0 @@ -package dev.aman.inquire.splashScreen - -import android.annotation.SuppressLint -import android.content.Intent -import androidx.appcompat.app.AppCompatActivity -import android.os.Bundle -import android.os.Handler - -import dev.aman.inquire.databinding.ActivityOrganisationSplashBinding -import dev.aman.inquire.organisation.OrganisationMainActivity - -@SuppressLint("CustomSplashScreen") -class OrganisationSplashActivity : AppCompatActivity() { - private lateinit var binding: ActivityOrganisationSplashBinding - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding= ActivityOrganisationSplashBinding.inflate(layoutInflater) - setContentView(binding.root) - Handler().postDelayed({ - val mIntent = Intent(this, OrganisationMainActivity::class.java) - startActivity(mIntent) - finish() - }, 6000) - - } -} \ No newline at end of file diff --git a/app/src/main/java/dev/aman/inquire/splashScreen/SplashActivity.kt b/app/src/main/java/dev/aman/inquire/splashScreen/SplashActivity.kt index 0d7d9d3..b2de34b 100644 --- a/app/src/main/java/dev/aman/inquire/splashScreen/SplashActivity.kt +++ b/app/src/main/java/dev/aman/inquire/splashScreen/SplashActivity.kt @@ -7,10 +7,9 @@ import android.os.Bundle import android.os.Handler import com.google.firebase.auth.ktx.auth import com.google.firebase.ktx.Firebase -import dev.aman.inquire.ChoosingActivity -import dev.aman.inquire.MainActivity import dev.aman.inquire.databinding.ActivitySplashBinding import dev.aman.inquire.individual.IndividualMainActivity +import dev.aman.inquire.individual.ui.login.IndividualLoginActivity @SuppressLint("CustomSplashScreen") class SplashActivity : AppCompatActivity() { @@ -29,7 +28,7 @@ class SplashActivity : AppCompatActivity() { }, 2000) } else{ - val mIntent = Intent(this@SplashActivity, ChoosingActivity::class.java) + val mIntent = Intent(this@SplashActivity,IndividualLoginActivity::class.java) startActivity(mIntent) finish() } diff --git a/app/src/main/java/dev/aman/inquire/utils/Constants.kt b/app/src/main/java/dev/aman/inquire/utils/Constants.kt new file mode 100644 index 0000000..9966d29 --- /dev/null +++ b/app/src/main/java/dev/aman/inquire/utils/Constants.kt @@ -0,0 +1,37 @@ +package dev.aman.inquire.utils + +object Constants { + val listOfLanguages = listOf( + "C", + "C++", + "Go", + "HTML/CSS", + "Java", + "JavaScript", + "Kotlin", + "Python", + "Ruby", + "Rust", + "Scala", + "Swift", + "TypeScript", + "Android", + "Kotlin", + "React-Native", + "Flutter", + "Dart", + "Elixir", + "Elastcic", + "Machine Learning" + ) + const val KEY_INPUT_CODE_DIALOG = "key_input_code_dialog" + + const val KEY_CODE = "key_code" + const val KEY_PUBLISHED_FIRST_SNIPPET = "key_published_first_Inquire" + + const val KEY_USER_PREFERRED_TAGS = "user_preferred_tags" + const val KEY_USER = "shared_pref_user" +} +enum class InquireState{ + Bookmarked,UnBookmarked +} \ No newline at end of file diff --git a/app/src/main/java/dev/aman/inquire/utils/DepthPageTransformer.kt b/app/src/main/java/dev/aman/inquire/utils/DepthPageTransformer.kt new file mode 100644 index 0000000..8d1f5f2 --- /dev/null +++ b/app/src/main/java/dev/aman/inquire/utils/DepthPageTransformer.kt @@ -0,0 +1,43 @@ +package dev.aman.inquire.utils + +import android.view.View +import androidx.viewpager2.widget.ViewPager2 +import kotlin.math.abs + +private const val MIN_SCALE = 0.75f +class DepthPageTransformer: ViewPager2.PageTransformer { + override fun transformPage(view: View, position: Float) { + view.apply { + val pageWidth = width + when { + position < -1 -> { // [-Infinity,-1) + // This page is way off-screen to the left. + alpha = 0f + } + position <= 0 -> { // [-1,0] + // Use the default slide transition when moving to the left page + alpha = 1f + translationX = 0f + scaleX = 1f + scaleY = 1f + } + position <= 1 -> { // (0,1] + // Fade the page out. + alpha = 1 - position + + // Counteract the default slide transition + translationX = pageWidth * -position + + // Scale the page down (between MIN_SCALE and 1) + val scaleFactor = (MIN_SCALE + (1 - MIN_SCALE) * (1 - abs(position))) + scaleX = scaleFactor + scaleY = scaleFactor + } + else -> { // (1,+Infinity] + // This page is way off-screen to the right. + alpha = 0f + } + } + } + } +} diff --git a/app/src/main/java/dev/aman/inquire/utils/Formate.kt b/app/src/main/java/dev/aman/inquire/utils/Formate.kt new file mode 100644 index 0000000..77189ca --- /dev/null +++ b/app/src/main/java/dev/aman/inquire/utils/Formate.kt @@ -0,0 +1,12 @@ +package dev.aman.inquire.utils + +import java.text.SimpleDateFormat +import java.util.* + +fun getFormattedDateTime(): String = run { + SimpleDateFormat("dd/MM/yy hh:mm aaa", Locale.ENGLISH).format(System.currentTimeMillis()) +} + +fun getUuid() = UUID.randomUUID().toString() + +fun getUniqueNameForImage() = "${getUuid()} ${getFormattedDateTime()}" diff --git a/app/src/main/java/dev/aman/inquire/utils/State.kt b/app/src/main/java/dev/aman/inquire/utils/State.kt new file mode 100644 index 0000000..47d906d --- /dev/null +++ b/app/src/main/java/dev/aman/inquire/utils/State.kt @@ -0,0 +1,7 @@ +package dev.aman.inquire.utils + +sealed class State { + object Loading : State() + class Success(val data: T) : State() + class Error(val message: String) : State() +} diff --git a/app/src/main/java/dev/aman/inquire/utils/Utils.kt b/app/src/main/java/dev/aman/inquire/utils/Utils.kt new file mode 100644 index 0000000..5cd465b --- /dev/null +++ b/app/src/main/java/dev/aman/inquire/utils/Utils.kt @@ -0,0 +1,40 @@ +package dev.aman.inquire.utils + +class Utils { + + companion object { + private const val SECOND_MILLIS = 1000 + private const val MINUTE_MILLIS = 60 * SECOND_MILLIS + private const val HOUR_MILLIS = 60 * MINUTE_MILLIS + private const val DAY_MILLIS = 24 * HOUR_MILLIS + + fun getTimeAgo(time: Long): String? { + val now: Long = System.currentTimeMillis() + if (time > now || time <= 0) { + return null + } + + val diff = now - time + return if (diff < MINUTE_MILLIS) { + "just now" + } else if (diff < 2 * MINUTE_MILLIS) { + "a minute ago" + } else if (diff < 50 * MINUTE_MILLIS) { + (diff / MINUTE_MILLIS).toString() + " minutes ago" + } else if (diff < 90 * MINUTE_MILLIS) { + "an hour ago" + } else if (diff < 24 * HOUR_MILLIS) { + (diff / HOUR_MILLIS).toString() + " hours ago" + } else if (diff < 48 * HOUR_MILLIS) { + "yesterday" + } else { + (diff / DAY_MILLIS).toString() + " days ago" + } + } + + + } + + + +} \ No newline at end of file diff --git a/app/src/main/res/drawable/active_bookmrked.xml b/app/src/main/res/drawable/active_bookmrked.xml new file mode 100644 index 0000000..4da5803 --- /dev/null +++ b/app/src/main/res/drawable/active_bookmrked.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/active_image_like.xml b/app/src/main/res/drawable/active_image_like.xml new file mode 100644 index 0000000..3edfe1d --- /dev/null +++ b/app/src/main/res/drawable/active_image_like.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/github_logo.png b/app/src/main/res/drawable/github_logo.png new file mode 100644 index 0000000..6359098 Binary files /dev/null and b/app/src/main/res/drawable/github_logo.png differ diff --git a/app/src/main/res/drawable/githun_png.png b/app/src/main/res/drawable/githun_png.png new file mode 100644 index 0000000..b312783 Binary files /dev/null and b/app/src/main/res/drawable/githun_png.png differ diff --git a/app/src/main/res/drawable/googlecon.png b/app/src/main/res/drawable/googlecon.png new file mode 100644 index 0000000..8cb4ca7 Binary files /dev/null and b/app/src/main/res/drawable/googlecon.png differ diff --git a/app/src/main/res/drawable/ic_about.xml b/app/src/main/res/drawable/ic_about.xml new file mode 100644 index 0000000..99848fc --- /dev/null +++ b/app/src/main/res/drawable/ic_about.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_add_24.xml b/app/src/main/res/drawable/ic_baseline_add_24.xml new file mode 100644 index 0000000..eb23254 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_add_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_add_a_photo_24.xml b/app/src/main/res/drawable/ic_baseline_add_a_photo_24.xml new file mode 100644 index 0000000..b4f90ff --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_add_a_photo_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_add_circle_24.xml b/app/src/main/res/drawable/ic_baseline_add_circle_24.xml new file mode 100644 index 0000000..2bb63e6 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_add_circle_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_attach_file_24.xml b/app/src/main/res/drawable/ic_baseline_attach_file_24.xml new file mode 100644 index 0000000..a396022 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_attach_file_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_biotech_24.xml b/app/src/main/res/drawable/ic_baseline_biotech_24.xml new file mode 100644 index 0000000..ede4ceb --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_biotech_24.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_baseline_bolt_24.xml b/app/src/main/res/drawable/ic_baseline_bolt_24.xml new file mode 100644 index 0000000..0c51762 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_bolt_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_bookmark_24.xml b/app/src/main/res/drawable/ic_baseline_bookmark_24.xml new file mode 100644 index 0000000..7e480e2 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_bookmark_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_bookmark_added_24.xml b/app/src/main/res/drawable/ic_baseline_bookmark_added_24.xml new file mode 100644 index 0000000..79ada3c --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_bookmark_added_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_cancel_24.xml b/app/src/main/res/drawable/ic_baseline_cancel_24.xml new file mode 100644 index 0000000..1ab7bac --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_cancel_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_check_24.xml b/app/src/main/res/drawable/ic_baseline_check_24.xml new file mode 100644 index 0000000..0432fa6 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_check_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_collections_24.xml b/app/src/main/res/drawable/ic_baseline_collections_24.xml new file mode 100644 index 0000000..ee0f693 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_collections_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_comment_24.xml b/app/src/main/res/drawable/ic_baseline_comment_24.xml new file mode 100644 index 0000000..d5d0ae4 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_comment_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_description_24.xml b/app/src/main/res/drawable/ic_baseline_description_24.xml new file mode 100644 index 0000000..a8c3eac --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_description_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_edit_24.xml b/app/src/main/res/drawable/ic_baseline_edit_24.xml new file mode 100644 index 0000000..6e432fa --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_edit_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_error_outline_24.xml b/app/src/main/res/drawable/ic_baseline_error_outline_24.xml new file mode 100644 index 0000000..adc3b69 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_error_outline_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_favorite_24.xml b/app/src/main/res/drawable/ic_baseline_favorite_24.xml new file mode 100644 index 0000000..8f2d698 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_favorite_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_favorite_border_24.xml b/app/src/main/res/drawable/ic_baseline_favorite_border_24.xml new file mode 100644 index 0000000..3edfe1d --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_favorite_border_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_home_24.xml b/app/src/main/res/drawable/ic_baseline_home_24.xml new file mode 100644 index 0000000..3a4c7da --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_home_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_inactive.xml b/app/src/main/res/drawable/ic_baseline_inactive.xml new file mode 100644 index 0000000..725ba7a --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_inactive.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_language_24.xml b/app/src/main/res/drawable/ic_baseline_language_24.xml new file mode 100644 index 0000000..3f70646 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_language_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_login_24.xml b/app/src/main/res/drawable/ic_baseline_login_24.xml new file mode 100644 index 0000000..af590f6 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_login_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_photo_camera_24.xml b/app/src/main/res/drawable/ic_baseline_photo_camera_24.xml new file mode 100644 index 0000000..13186de --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_photo_camera_24.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_baseline_refresh_24.xml b/app/src/main/res/drawable/ic_baseline_refresh_24.xml new file mode 100644 index 0000000..f2be45b --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_refresh_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_settings_24.xml b/app/src/main/res/drawable/ic_baseline_settings_24.xml new file mode 100644 index 0000000..41a82ed --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_settings_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_thumb_up_24.xml b/app/src/main/res/drawable/ic_baseline_thumb_up_24.xml new file mode 100644 index 0000000..3028ac4 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_thumb_up_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_video_call_24.xml b/app/src/main/res/drawable/ic_baseline_video_call_24.xml new file mode 100644 index 0000000..218f7cc --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_video_call_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_bookmark.xml b/app/src/main/res/drawable/ic_bookmark.xml new file mode 100644 index 0000000..bcb76cd --- /dev/null +++ b/app/src/main/res/drawable/ic_bookmark.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_dashboard_black_24dp.xml b/app/src/main/res/drawable/ic_dashboard_black_24dp.xml new file mode 100644 index 0000000..46fc8de --- /dev/null +++ b/app/src/main/res/drawable/ic_dashboard_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_draft.xml b/app/src/main/res/drawable/ic_draft.xml new file mode 100644 index 0000000..b16a79b --- /dev/null +++ b/app/src/main/res/drawable/ic_draft.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_email.xml b/app/src/main/res/drawable/ic_email.xml new file mode 100644 index 0000000..6943b4c --- /dev/null +++ b/app/src/main/res/drawable/ic_email.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_home_black_24dp.xml b/app/src/main/res/drawable/ic_home_black_24dp.xml new file mode 100644 index 0000000..f8bb0b5 --- /dev/null +++ b/app/src/main/res/drawable/ic_home_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_inquire_title.xml b/app/src/main/res/drawable/ic_inquire_title.xml new file mode 100644 index 0000000..a18c703 --- /dev/null +++ b/app/src/main/res/drawable/ic_inquire_title.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_notifications_black_24dp.xml b/app/src/main/res/drawable/ic_notifications_black_24dp.xml new file mode 100644 index 0000000..78b75c3 --- /dev/null +++ b/app/src/main/res/drawable/ic_notifications_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_outline_arrow_upward_24.xml b/app/src/main/res/drawable/ic_outline_arrow_upward_24.xml new file mode 100644 index 0000000..07b7a83 --- /dev/null +++ b/app/src/main/res/drawable/ic_outline_arrow_upward_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_search.xml b/app/src/main/res/drawable/ic_search.xml new file mode 100644 index 0000000..07b76d6 --- /dev/null +++ b/app/src/main/res/drawable/ic_search.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/img.png b/app/src/main/res/drawable/img.png new file mode 100644 index 0000000..cddef2a Binary files /dev/null and b/app/src/main/res/drawable/img.png differ diff --git a/app/src/main/res/drawable/img_1.png b/app/src/main/res/drawable/img_1.png new file mode 100644 index 0000000..225c7ea Binary files /dev/null and b/app/src/main/res/drawable/img_1.png differ diff --git a/app/src/main/res/drawable/inactive_logo.xml b/app/src/main/res/drawable/inactive_logo.xml new file mode 100644 index 0000000..3edfe1d --- /dev/null +++ b/app/src/main/res/drawable/inactive_logo.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/font/firasansbold.ttf b/app/src/main/res/font/firasansbold.ttf new file mode 100644 index 0000000..e3593fb Binary files /dev/null and b/app/src/main/res/font/firasansbold.ttf differ diff --git a/app/src/main/res/font/firasansextrabold.ttf b/app/src/main/res/font/firasansextrabold.ttf new file mode 100644 index 0000000..83744c1 Binary files /dev/null and b/app/src/main/res/font/firasansextrabold.ttf differ diff --git a/app/src/main/res/font/firasansregular.ttf b/app/src/main/res/font/firasansregular.ttf new file mode 100644 index 0000000..6f80647 Binary files /dev/null and b/app/src/main/res/font/firasansregular.ttf differ diff --git a/app/src/main/res/font/sloganfont.ttf b/app/src/main/res/font/sloganfont.ttf new file mode 100644 index 0000000..3774ef5 Binary files /dev/null and b/app/src/main/res/font/sloganfont.ttf differ diff --git a/app/src/main/res/font/splashfont.ttf b/app/src/main/res/font/splashfont.ttf new file mode 100644 index 0000000..d2190b5 Binary files /dev/null and b/app/src/main/res/font/splashfont.ttf differ diff --git a/app/src/main/res/layout/activity_choosing.xml b/app/src/main/res/layout/activity_choosing.xml deleted file mode 100644 index 9b91e16..0000000 --- a/app/src/main/res/layout/activity_choosing.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - -