[Huawei Developers] Onurcan.Keskin:
View attachment 5178339

Building Activities for this Project

Before passing to the specialized flavor dimension let’s build:

Main Activity (Part-II)

Record Activity (Part-III)

Single Player (Fullscreen) Activity (Part-IV)

Profile Activity & Bonus Content (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>

View attachment 5178341 View attachment 5178345

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 attachment 5178347

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

View attachment 5178351

------------------------------

END OF PART - V