Profile Activity
On this part, we won’t be using any of the Exo Player or Video Kit. Our job here is to give the user to control his/her/them videos shareability, deleteability, or ability to watch those videos on the larger player under previously created Single Player either with Exo Player or with Video Kit.
So in this part, we’ll be using 3 items on a row kinda Grid layout manager of recycler view with some animations.
Let’s start by creating single items for this grid:
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="@dimen/grid_video"
android:layout_height="@dimen/grid_video"
android:layout_margin="3dp"
android:clickable="true"
android:focusable="true"
android:foreground="@drawable/round_ripple"
app:cardCornerRadius="10dp">
<!-- Front View -->
<RelativeLayout
android:id="@+id/vid_front"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackgroundBorderless"
android:background="@drawable/ic_rectangle_orange"
android:visibility="visible">
<com.klinker.android.simple_videoview.SimpleVideoView
android:id="@+id/grid_video"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:soundEffectsEnabled="false"
app:loop="true"
app:muted="true"
app:showSpinner="true"
app:stopSystemAudio="false" />
<ImageButton
android:id="@+id/pp_button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/transparent"
android:contentDescription="@string/play_pause_button"
android:src="@drawable/ic_pause"
android:visibility="gone" />
<ImageView
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_marginEnd="0dp"
android:layout_marginBottom="0dp"
android:contentDescription="@string/image"
android:padding="3dp"
android:src="@drawable/ic_image" />
</RelativeLayout>
<!-- Back View -->
<LinearLayout
android:id="@+id/vid_back"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/ic_rectangle_orange"
android:orientation="vertical"
android:padding="5dp"
android:visibility="gone"
android:weightSum="4">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/big_player"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:clickable="true"
android:ellipsize="end"
android:focusable="true"
android:foreground="@drawable/round_ripple"
android:gravity="center_vertical"
android:maxEms="1"
android:maxLines="1"
android:text="@string/fullscreen"
android:textColor="@color/white"
app:drawableStartCompat="@drawable/ic_fullscreen" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:background="@color/purple_700" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/share"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:clickable="true"
android:ellipsize="end"
android:focusable="true"
android:foreground="@drawable/round_ripple"
android:gravity="center_vertical"
android:maxEms="1"
android:maxLines="1"
android:text="@string/hide"
android:textColor="@color/white"
app:drawableStartCompat="@drawable/ic_hide" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:background="@color/purple_700" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/delete"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:clickable="true"
android:ellipsize="end"
android:focusable="true"
android:foreground="@drawable/round_ripple"
android:gravity="center_vertical"
android:maxEms="1"
android:maxLines="1"
android:text="@string/delete"
android:textColor="@color/white"
app:drawableStartCompat="@drawable/ic_delete" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:background="@color/purple_700" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/cancel"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:clickable="true"
android:ellipsize="end"
android:focusable="true"
android:foreground="@drawable/round_ripple"
android:gravity="center_vertical"
android:maxEms="1"
android:maxLines="1"
android:text="@string/cancel"
android:textColor="@color/white"
app:drawableStartCompat="@drawable/ic_cancel" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>


Now to our profile activities layout:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/colour_bg"
android:padding="10dp"
tools:context=".ui.activities.ProfileActivity">
<!-- Banner -->
<LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/profile_image"
android:layout_width="0dp"
android:layout_height="@dimen/profile_image"
android:layout_weight=".4"
app:civ_border_color="@color/white"
app:civ_border_width="1dp"
tools:src="@drawable/ic_person" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="@dimen/profile_image"
android:layout_weight="1.5"
android:orientation="vertical"
android:weightSum="1">
<TextView
android:id="@+id/profile_total_video"
style="@style/TextAppearance.AppCompat.Large"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight=".5"
android:fontFamily="@font/phenomena_regular"
android:gravity="center"
android:textColor="@color/white"
tools:text="0" />
<TextView
style="@style/TextAppearance.AppCompat.Large"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight=".5"
android:fontFamily="@font/bicubik"
android:gravity="center"
android:text="@string/videos"
android:textColor="@color/white" />
</LinearLayout>
<ImageButton
android:id="@+id/prof_settings"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_weight=".1"
android:background="@color/transparent"
android:clickable="true"
android:contentDescription="@string/settings"
android:focusable="true"
android:foreground="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_setting" />
</LinearLayout>
<View
android:id="@+id/view2"
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:background="@color/darker_light_fuchsia"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/linearLayout2" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/grid_recycler"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/view2"
tools:listitem="@layout/grid_video_item" />
</androidx.constraintlayout.widget.ConstraintLayout>

View Holder for our grid view:
class ProfileGridViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val parent: View = itemView
private val simpleVideo: SimpleVideoView
val ppButton: ImageView
val vidBack: LinearLayout
val vidFront: RelativeLayout
val bigPlayer: TextView
val cancel: TextView
val delete: TextView
val share: TextView
fun bindImage(videoUrl: String) {
simpleVideo.start(Uri.parse(videoUrl))
}
fun startStop() {
if (simpleVideo.isPlaying) {
simpleVideo.pause()
ppButton.visibility = View.VISIBLE
ppButton.setImageResource(R.drawable.ic_pause)
val timer = Timer()
timer.schedule(object : TimerTask() {
override fun run() {
ppButton.expandView()
}
}, 3000)
} else {
simpleVideo.play()
ppButton.visibility = View.VISIBLE
ppButton.setImageResource(R.drawable.ic_play)
val timer = Timer()
timer.schedule(object : TimerTask() {
override fun run() {
ppButton.expandView()
}
}, 3000)
}
}
fun startSinglePlayer(videoUrl: String) {
bigPlayer.setOnClickListener {
parent.context.startActivity(
Intent(parent.context, SinglePlayerActivity::class.java)
.putExtra("url", videoUrl)
.putExtra("type", 0)
)
}
}
init {
simpleVideo = parent.findViewById(R.id.grid_video)
ppButton = parent.findViewById(R.id.pp_button)
vidBack = parent.findViewById(R.id.vid_back)
vidFront = parent.findViewById(R.id.vid_front)
bigPlayer = parent.findViewById(R.id.big_player)
cancel = parent.findViewById(R.id.cancel)
delete = parent.findViewById(R.id.delete)
share = parent.findViewById(R.id.share)
}
}
Then interface to our profile:
class IProfile {
interface ViewProfile{
fun onViewsCreate()
fun populateViews()
fun setupRecycler()
}
}
Finally on our activity:
class ProfileActivity : AppCompatActivity(), IProfile.ViewProfile {
private lateinit var binding: ActivityProfileBinding
private val profilePresenter: ProfilePresenter by lazy {
ProfilePresenter()
}
…
}
Let’s start by filling overridden methods and custom ones:
- onViewsCreate()
override fun onViewsCreate() {
binding.gridRecycler.layoutManager = GridLayoutManager(this, 3)
binding.gridRecycler.setHasFixedSize(true)
}
- PopulateViews()
fun populateViews() {
Constants.fUserInfoDB.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val img = snapshot.child("photoUrl").value.toString()
val name = snapshot.child("nameSurname").value.toString()
Picasso.get().load(img).centerCrop().fit().into(binding.profileImage)
supportActionBar?.title = getString(R.string.welcome, name)
}
override fun onCancelled(error: DatabaseError) {
showLogError(Constants.mProfileActivity, error.message)
}
})
Constants.fFeedRef.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val pTotal = NumberConvertor.prettyCount(snapshot.children.count())
binding.profileTotalVideo.text = pTotal
}
override fun onCancelled(error: DatabaseError) {
showLogError(Constants.mProfileActivity, error.toString())
}
})
}
- Setting up recycler:
override fun setupRecycler() {
val options = FirebaseRecyclerOptions.Builder<DataClass.ProfileVideoDataClass>()
.setQuery(Constants.fFeedRef, DataClass.ProfileVideoDataClass::class.java).build()
val adapterFire = object :
FirebaseRecyclerAdapter<DataClass.ProfileVideoDataClass, ProfileGridViewHolder>(options) {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): ProfileGridViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.grid_video_item, parent, false)
return ProfileGridViewHolder(view)
}
override fun onBindViewHolder(
holder: ProfileGridViewHolder,
position: Int,
model: DataClass.ProfileVideoDataClass
) {
val lisResUid = getRef(position).key
val scale = this@ProfileActivity.applicationContext.resources.displayMetrics.density
holder.vidFront.cameraDistance = 8000 * scale
holder.vidBack.cameraDistance = 8000 * scale
val frontAnim =
AnimatorInflater.loadAnimator(
this@ProfileActivity,
R.animator.front_animator
) as AnimatorSet
val backAnim = AnimatorInflater.loadAnimator(
this@ProfileActivity,
R.animator.back_animator
) as AnimatorSet
val dbRef = FirebaseDbHelper.getVideoFeedItem(AppUser.getUserId(), lisResUid!!)
dbRef.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
mShared = snapshot.child("shareStat").value.toString()
when (mShared) {
"1" -> {
holder.share.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.ic_hide,
0,
0,
0
)
holder.share.text = getString(R.string.hide)
holder.share.setOnClickListener {
profilePresenter.moveShowToHide(this@ProfileActivity, lisResUid)
}
}
"0" -> {
holder.share.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.ic_show,
0,
0,
0
)
holder.share.text = getString(R.string.share)
holder.share.setOnClickListener {
profilePresenter.moveHideToShow(this@ProfileActivity, lisResUid)
}
}
}
}
override fun onCancelled(error: DatabaseError) {
showLogError(Constants.mProfileActivity, error.message)
}
})
holder.startSinglePlayer(model.videoUrl)
holder.vidFront.setOnClickListener {
frontAnim.setTarget(holder.vidFront)
backAnim.setTarget(holder.vidBack)
frontAnim.start()
backAnim.start()
holder.vidFront.visibility = View.GONE
holder.vidBack.visibility = View.VISIBLE
holder.cancel.setOnClickListener {
frontAnim.setTarget(holder.vidBack)
backAnim.setTarget(holder.vidFront)
frontAnim.start()
backAnim.start()
holder.vidFront.visibility = View.VISIBLE
holder.vidBack.visibility = View.GONE
}
}
holder.bindImage(model.videoUrl)
//holder.simpleVideo.setOnClickListener { holder.startStop() }
}
}
adapterFire.startListening()
binding.gridRecycler.adapter = adapterFire
}
- OnCreate:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityProfileBinding.inflate(layoutInflater)
setContentView(binding.root)
Slidr.attach(this)
onViewsCreate()
populateViews()
}
Final result for activity

Pages: 1 2