diff --git a/app/build.gradle.kts b/app/build.gradle.kts index fbd4458..1b6befb 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -63,6 +63,7 @@ dependencies { implementation(libs.play.services.location) implementation(libs.androidx.recyclerview) implementation(libs.androidx.media3.ui) + implementation(libs.firebase.database.ktx) val room_version = "2.6.1" val lifecycle_version = "2.8.1" val mediaVersion = "1.3.1" diff --git a/app/src/androidTest/java/com/example/trainhub/PostFireBaseModelTest.kt b/app/src/androidTest/java/com/example/trainhub/PostFireBaseModelTest.kt deleted file mode 100644 index a4d2777..0000000 --- a/app/src/androidTest/java/com/example/trainhub/PostFireBaseModelTest.kt +++ /dev/null @@ -1,106 +0,0 @@ -package com.example.trainhub - - -import com.example.trainhub.models.entities.Post -import com.example.trainhub.models.fireBaseModels.PostFireBaseModel -import org.junit.Test -import org.junit.Assert.* -import java.util.concurrent.CountDownLatch -import java.util.concurrent.TimeUnit - -class PostFirebaseModelTask{ - - private val PostFireBaseModel = PostFireBaseModel() - private val id = "Another Test" - private val title = "asdfasd Test 2" - private val description = " asdfdasf updated 2" - private val imageUrl = " asdfasdf Test " - private val userId = "Test User Id" - private val workoutCategory = "Test Workout Category ddd 2" - private val location = "Test Location ddasd 2" - private val lastUpdated: Long? = null - - @Test - fun addPost(){ - val post = Post(id,title, description, imageUrl, userId, workoutCategory, location) - var result: Boolean? = null - val latch = CountDownLatch(1) - - PostFireBaseModel.addPostDocument(post){ isAddedToFireStore-> - result = isAddedToFireStore - latch.countDown() - } - - latch.await(5, TimeUnit.SECONDS) - assertEquals(true, result) - } - - @Test - fun updatePost(){ - val post = Post("test id",title, description, imageUrl, userId, workoutCategory, location) - var result: Boolean? = null - val latch = CountDownLatch(1) - - PostFireBaseModel.updatePostDocument(post){ isUpdatedInFireStore-> - result = isUpdatedInFireStore - latch.countDown() - } - - latch.await(5, TimeUnit.SECONDS) - assertEquals(true, result) - } - - @Test - fun deletePost(){ - val post = Post("test id",title, description, imageUrl, userId, workoutCategory, location) - var result: Boolean? = null - val latch = CountDownLatch(1) - - PostFireBaseModel.deletePostDocument(post){ isDeletedFromFireStore-> - result = isDeletedFromFireStore - latch.countDown() - } - - latch.await(5, TimeUnit.SECONDS) - assertEquals(true, result) - } - - @Test - fun getAllPosts(){ - var result: List? = null - val latch = CountDownLatch(1) - - PostFireBaseModel.getAllPostsDocument{ posts-> - result = posts - latch.countDown() - } - - latch.await(5, TimeUnit.SECONDS) - println("TEST GET ALL POSTS") - println("-------------------") - println(result) - println("-------------------") - assertNotNull(result) - } - - @Test - fun getPostsByUid(){ - var result: List? = null - val latch = CountDownLatch(1) - - PostFireBaseModel.getPostsByUid(userId){ posts-> - result = posts - latch.countDown() - } - - latch.await(5, TimeUnit.SECONDS) - println("TEST GET ALL POSTS OF USER ID") - println("-------------------") - println(result) - println(result?.size) - println("-------------------") - assertNotNull(result) - } - - -} \ No newline at end of file diff --git a/app/src/androidTest/java/com/example/trainhub/UserFirebaseModelTest.kt b/app/src/androidTest/java/com/example/trainhub/UserFirebaseModelTest.kt deleted file mode 100644 index 45aef92..0000000 --- a/app/src/androidTest/java/com/example/trainhub/UserFirebaseModelTest.kt +++ /dev/null @@ -1,124 +0,0 @@ -//import android.content.ContentValues.TAG -//import android.nfc.Tag -//import android.util.Log -//import com.example.trainhub.models.entities.User -//import kotlinx.coroutines.runBlocking -//import org.junit.Test -//import org.junit.Assert.* -//import com.example.trainhub.models.fireBaseModels.UserFireBaseModel -//import com.google.firebase.auth.FirebaseAuth -//import com.google.firebase.auth.FirebaseUser -//import com.google.protobuf.Internal.BooleanList -//import java.util.Date -//import java.util.concurrent.CountDownLatch -//import java.util.concurrent.TimeUnit -// -//class UserFirebaseModelTask { -// -// -// private val userFbModel: UserFireBaseModel = UserFireBaseModel() -// private val email: String = "test@test.com" -// private val password: String = "123456" -// private val latch = CountDownLatch(1) -// private val uid: String? = null -// private val user: User? = null -// private var userAuth: FirebaseUser?= null -// -// @Test -// fun addition_isCorrect() { -// assertEquals(4, 2 + 2) -// } -// -// @Test -// fun testRegisterSuccess() { -// val latch = CountDownLatch(1) -// var result: String? = null -// var uid: String? = null -// -// userFbModel.register(email, password) { uidResult -> -// println("======= Success UID: $uidResult") -//// userAuth = result -// uid = uidResult -// latch.countDown() -// } -// -// latch.await(5, TimeUnit.SECONDS) // wait for the callback -// assertNotNull(uid) -// } -// -// @Test -// fun testSignInSuccess(){ -// var result: Boolean = false -// userFbModel.signIn(email,password){ signedIn -> -// if(signedIn) -// result = true -// latch.countDown() -// } -// val success = latch.await(5, TimeUnit.SECONDS) -// -// assertEquals(true, success) -// assertEquals(true, result != null) -// -// Log.i(TAG,"Test signInSuccess UID: $result") -// } -// -// @Test -// fun testAddUserSuccess() { -// val newUser = User( -// id = "testUid", -// email = email, -//// password = password, -// profileImageUrl = "test_profile_image_url", -// lastUpdated = System.currentTimeMillis() -// ) -// -// val latch = CountDownLatch(1) -// var result: Boolean? = null -// -// userFbModel.addUserDocument(newUser) { success -> -// result = success -// latch.countDown() -// } -// -// latch.await(5, TimeUnit.SECONDS) // wait for the callback -// -// assertEquals(true, result) -// } -// -// @Test -// fun testRegisterFailure() { -// val userFbModel = UserFireBaseModel() -// val email = "invalidemail" -// val password = "123" -// val latch = CountDownLatch(1) -// var result: String? = null -// -// userFbModel.register(email, password) { -//// result = it -// latch.countDown() -// } -// -// latch.await(5, TimeUnit.SECONDS) // wait for the callback -// -// assertNull(result) -// } -// -// @Test -// fun testDeleteUserAuth(){ -// var result: Boolean = false -// val latch = CountDownLatch(1) -// userFbModel.deleteUserAuth() { -// result = true -// latch.countDown() -// } -// latch.await(5, TimeUnit.SECONDS) -// assertEquals(true, result) -// } -// -// @Test -// fun f(){ -// testRegisterSuccess() -// testDeleteUserAuth() -// } -// -//} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2d9b199..e13ebe6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,15 +20,13 @@ tools:targetApi="34"> + android:value="${GOOGLE_API_KEY}" /> - - diff --git a/app/src/main/java/com/example/trainhub/MainActivity.kt b/app/src/main/java/com/example/trainhub/MainActivity.kt index f485c02..340938f 100644 --- a/app/src/main/java/com/example/trainhub/MainActivity.kt +++ b/app/src/main/java/com/example/trainhub/MainActivity.kt @@ -15,7 +15,6 @@ import com.example.trainhub.fragments.LocationFragment import com.example.trainhub.fragments.ProfileFragment import com.google.android.material.bottomnavigation.BottomNavigationView - class MainActivity : AppCompatActivity() { private var navController: NavController? = null private val homeFragment = HomeFragment() @@ -35,7 +34,6 @@ class MainActivity : AppCompatActivity() { } - bottomNavigationView?.setOnItemSelectedListener { when(it.itemId){ R.id.icHome -> replaceFragment(homeFragment) @@ -44,6 +42,7 @@ class MainActivity : AppCompatActivity() { R.id.icLocation -> replaceFragment(locationFragment) R.id.icProfile -> replaceFragment(profileFragment) } + true } @@ -57,43 +56,19 @@ class MainActivity : AppCompatActivity() { } } - bottomNavigationView?.setOnItemSelectedListener { item -> - when (item.itemId) { - - R.id.icHome -> { - - navController?.navigate(R.id.homeFragment) - true - } - R.id.icDiscover -> { - - navController?.navigate(R.id.discoverFragment) - true - } - R.id.icAddPost -> { - navController?.navigate(R.id.addPostFragment) - true - } - R.id.icLocation -> { - navController?.navigate(R.id.locationFragment) - true - } - R.id.icProfile -> { - navController?.navigate(R.id.profileFragment) - true - } - else -> false - } - } } + fun moveToHome(){ bottomNavigationView?.selectedItemId = R.id.icHome replaceFragment(homeFragment) } - fun replaceFragment(fragment: Fragment){ + fun replaceFragment(fragment: Fragment,bundle: Bundle? = null){ + if(bundle!=null){ + fragment.arguments = bundle + } if(fragment!=null){ val transaction = supportFragmentManager.beginTransaction() transaction.replace(R.id.navHostMain,fragment) diff --git a/app/src/main/java/com/example/trainhub/adapters/PostRecyclerAdapter.kt b/app/src/main/java/com/example/trainhub/adapters/PostRecyclerAdapter.kt index a2c51b8..0defab5 100644 --- a/app/src/main/java/com/example/trainhub/adapters/PostRecyclerAdapter.kt +++ b/app/src/main/java/com/example/trainhub/adapters/PostRecyclerAdapter.kt @@ -15,14 +15,17 @@ import com.example.trainhub.viewModel.PostWithUser import com.google.firebase.ktx.Firebase import com.google.firebase.storage.ktx.storage -class PostRecyclerAdapter(var posts: List) : +class PostRecyclerAdapter(var posts: List, private var isClickable:Boolean) : + RecyclerView.Adapter() { val storage = Firebase.storage inner class PostViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + val profileImg: ImageFilterView = itemView.findViewById(R.id.ifPostProfileImg) val titleTextView: TextView = itemView.findViewById(R.id.tvCardTitle) val descriptionTextView: TextView = itemView.findViewById(R.id.tvDescription) val postImg: ImageView = itemView.findViewById(R.id.ifPostImg) + } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PostViewHolder { @@ -45,6 +48,15 @@ class PostRecyclerAdapter(var posts: List) : .load(currentItem.user?.profileImageUrl) .into(holder.profileImg) Log.d(TAG,"PROFILE IMAGE: profile_images/${currentItem.user?.profileImageUrl}") + + + if (isClickable) { + holder.itemView.setOnClickListener { + Log.d("post", "Item clicked: ${currentItem.post.title}") + } + + } + } override fun getItemCount(): Int { diff --git a/app/src/main/java/com/example/trainhub/fragments/AddPostFragment.kt b/app/src/main/java/com/example/trainhub/fragments/AddPostFragment.kt index 5b4dc1a..9977acc 100644 --- a/app/src/main/java/com/example/trainhub/fragments/AddPostFragment.kt +++ b/app/src/main/java/com/example/trainhub/fragments/AddPostFragment.kt @@ -8,6 +8,7 @@ import android.location.Location import android.net.Uri import android.os.Bundle import android.provider.MediaStore +import android.util.Log import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View diff --git a/app/src/main/java/com/example/trainhub/fragments/HomeFragment.kt b/app/src/main/java/com/example/trainhub/fragments/HomeFragment.kt index 4cf7327..170c86e 100644 --- a/app/src/main/java/com/example/trainhub/fragments/HomeFragment.kt +++ b/app/src/main/java/com/example/trainhub/fragments/HomeFragment.kt @@ -42,7 +42,7 @@ class HomeFragment : Fragment() , SwipeRefreshLayout.OnRefreshListener{ } postsRecyclerView?.layoutManager = LinearLayoutManager(context) - postAdapter = PostRecyclerAdapter(listOf()) + postAdapter = PostRecyclerAdapter(listOf(), false) postsRecyclerView?.adapter = postAdapter return view diff --git a/app/src/main/java/com/example/trainhub/fragments/ProfileFragment.kt b/app/src/main/java/com/example/trainhub/fragments/ProfileFragment.kt index c4a69c6..62e22d8 100644 --- a/app/src/main/java/com/example/trainhub/fragments/ProfileFragment.kt +++ b/app/src/main/java/com/example/trainhub/fragments/ProfileFragment.kt @@ -1,22 +1,185 @@ package com.example.trainhub.fragments +import android.app.Activity +import android.content.Intent +import android.net.Uri import android.os.Bundle +import android.provider.MediaStore +import android.util.Log import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Button +import android.widget.EditText +import android.widget.ImageView +import android.widget.ProgressBar +import android.widget.TextView +import android.widget.Toast +import androidx.activity.result.ActivityResult +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts +import androidx.lifecycle.Observer +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide import com.example.trainhub.R +import com.example.trainhub.TrainHubApplication +import com.example.trainhub.adapters.PostRecyclerAdapter +import com.example.trainhub.models.entities.User +import com.example.trainhub.services.SharedPrefHelper +import com.example.trainhub.viewModel.PostWithUser +import com.example.trainhub.viewModel.ProfileViewModel class ProfileFragment : Fragment() { - - + private val pb: ProgressBar? = null + private lateinit var recyclerViewPosts: RecyclerView + private lateinit var postsAdapter: PostRecyclerAdapter + private var postsList: List = listOf() + private val profileViewModel: ProfileViewModel = ProfileViewModel() + private var name: TextView? = null + private var email:TextView? = null + private var profilePic:ImageView? = null + private var btnEdit : Button? = null + private lateinit var imagePickerLauncher: ActivityResultLauncher + private var selectedImageUri: Uri? = null + private var filePath: String? = null + private var userId: String? = null + private var lastUpdated: Long = 0 override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { - // Inflate the layout for this fragment - return inflater.inflate(R.layout.fragment_profile, container, false) + + val view = inflater.inflate(R.layout.fragment_profile, container, false) + profileViewModel.profilePic.observe(viewLifecycleOwner, Observer { newProfilePic -> + Glide.with(this).load(newProfilePic).into(profilePic!!) + }) + userId = TrainHubApplication.Globals.currentUser?.id + name = view.findViewById(R.id.etName) + email = view.findViewById(R.id.tvEmail) + profilePic = view.findViewById(R.id.ivProfile) + btnEdit = view.findViewById(R.id.btnEdit) + imagePickerLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){loadedProfileImageInPickerHandler(it)} + + val sharedPrefHelper = SharedPrefHelper(requireContext()) + email?.text = TrainHubApplication.Globals.currentUser?.email + name?.text = TrainHubApplication.Globals.currentUser?.name + lastUpdated = TrainHubApplication.Globals.currentUser?.lastUpdated!! + + + val savedImageUri = sharedPrefHelper.getProfilePicUri() + Log.d("ProfileFragment", "Saved Image URI: $savedImageUri") + if (savedImageUri != null) { + Glide.with(this).load(savedImageUri).into(profilePic!!) + } else { + Glide.with(this).load(R.drawable.user_profile).into(profilePic!!) + } + + btnEdit?.setOnClickListener { + val view = layoutInflater.inflate(R.layout.dialog_update_name, null) + val oldN = view.findViewById(R.id.old_name) + val newN = view.findViewById(R.id.new_name) + val builder = android.app.AlertDialog.Builder(context) + oldN.setText(name?.text) + val currentName = oldN.text.toString() + oldN.isEnabled = false + builder.setView(view) + val dialog = builder.create() + dialog.show() + view.findViewById