Exo Player — HMS Video Kit Comparison by building a flavored Android Application . Part V

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>
Front view
Back view

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