diff --git a/.idea/misc.xml b/.idea/misc.xml
index 0fc7958..309a2d3 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -5,11 +5,14 @@
diff --git a/app/build.gradle b/app/build.gradle
index 0a936d8..e7edea2 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -54,6 +54,7 @@ dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.1.5")
implementation "com.google.accompanist:accompanist-insets:0.24.2-alpha"
+ implementation "androidx.constraintlayout:constraintlayout-compose:1.0.0"
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
diff --git a/app/src/main/java/dev/baseio/composeplayground/MainActivity.kt b/app/src/main/java/dev/baseio/composeplayground/MainActivity.kt
index 4418d87..8447a86 100644
--- a/app/src/main/java/dev/baseio/composeplayground/MainActivity.kt
+++ b/app/src/main/java/dev/baseio/composeplayground/MainActivity.kt
@@ -7,19 +7,35 @@ import android.view.View
import android.view.WindowManager
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
-import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
-import com.google.accompanist.insets.*
+import com.google.accompanist.insets.ProvideWindowInsets
import com.google.accompanist.pager.ExperimentalPagerApi
import com.google.accompanist.pager.HorizontalPager
import com.google.accompanist.pager.HorizontalPagerIndicator
import com.google.accompanist.pager.rememberPagerState
-import dev.baseio.composeplayground.ui.animations.*
+import dev.baseio.composeplayground.ui.animations.AndroidMadSkills
+import dev.baseio.composeplayground.ui.animations.BellAnimation
+import dev.baseio.composeplayground.ui.animations.ChatMessageReactions
+import dev.baseio.composeplayground.ui.animations.Github404
+import dev.baseio.composeplayground.ui.animations.GlowingRingLoader
+import dev.baseio.composeplayground.ui.animations.IOSSleepSchedule
+import dev.baseio.composeplayground.ui.animations.LikeAnimation
+import dev.baseio.composeplayground.ui.animations.MenuToClose
+import dev.baseio.composeplayground.ui.animations.NetflixIntroAnimation
+import dev.baseio.composeplayground.ui.animations.ScalingRotatingLoader
+import dev.baseio.composeplayground.ui.animations.ShootingStarsAnimation
+import dev.baseio.composeplayground.ui.animations.TwitterSplashAnimation
+import dev.baseio.composeplayground.ui.animations.YahooWeatherAndSun
+import dev.baseio.composeplayground.ui.animations.copyfile.CopyFile
+import dev.baseio.composeplayground.ui.animations.copyfile.CopyFile2
import dev.baseio.composeplayground.ui.animations.planetarysystem.PlanetarySystem
import dev.baseio.composeplayground.ui.animations.pulltorefresh.PullToRefreshOne
import dev.baseio.composeplayground.ui.theme.ComposePlaygroundTheme
@@ -62,7 +78,7 @@ class MainActivity : ComponentActivity() {
) {
HorizontalPager(
modifier = Modifier.fillMaxSize(),
- count = 15, state = pagerState,
+ count = 17, state = pagerState,
) { page ->
// Our page content
when (page) {
@@ -93,6 +109,16 @@ class MainActivity : ComponentActivity() {
14 -> {
ShootingStarsAnimation()
}
+ 15 -> {
+ Box(modifier = Modifier.fillMaxSize()) {
+ CopyFile()
+ }
+ }
+ 16 -> {
+ Box(modifier = Modifier.fillMaxSize()) {
+ CopyFile2()
+ }
+ }
6 -> {
NetflixIntroAnimation()
}
diff --git a/app/src/main/java/dev/baseio/composeplayground/contributors/PushpalRoy.kt b/app/src/main/java/dev/baseio/composeplayground/contributors/PushpalRoy.kt
new file mode 100644
index 0000000..e42adf6
--- /dev/null
+++ b/app/src/main/java/dev/baseio/composeplayground/contributors/PushpalRoy.kt
@@ -0,0 +1,48 @@
+package dev.baseio.composeplayground.contributors
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Surface
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import dev.baseio.composeplayground.R
+import dev.baseio.composeplayground.ui.theme.Typography
+
+const val pushpalRoyImageUrl = "https://ca.slack-edge.com/T02TLUWLZ-US7QYGQL9-2bba9d14df28-512"
+
+@Composable
+fun PushpalRoy(modifier: Modifier = Modifier) {
+ Row(verticalAlignment = Alignment.CenterVertically, modifier = modifier.padding(4.dp)) {
+ CoilImageBox(Modifier.size(64.dp), pushpalRoyImageUrl)
+ Column(verticalArrangement = Arrangement.Center, modifier = Modifier.padding(8.dp)) {
+ Text(
+ modifier = Modifier.padding(bottom = 6.dp),
+ text = stringResource(id = R.string.emp_mmh0230),
+ style = Typography.h6.copy(MaterialTheme.colors.onSurface),
+ )
+ Text(
+ text = stringResource(id = R.string.emp_mmh0230_email),
+ style = Typography.body2.copy(MaterialTheme.colors.onSurface),
+ color = Color(0xFFCACACA)
+ )
+ }
+ }
+}
+
+@Preview("Pushpal Roy Preview")
+@Composable
+fun PreviewPushpalRoy() {
+ Surface {
+ PushpalRoy()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/dev/baseio/composeplayground/ui/animations/copyfile/CopyFile.kt b/app/src/main/java/dev/baseio/composeplayground/ui/animations/copyfile/CopyFile.kt
new file mode 100644
index 0000000..b9d3ab7
--- /dev/null
+++ b/app/src/main/java/dev/baseio/composeplayground/ui/animations/copyfile/CopyFile.kt
@@ -0,0 +1,334 @@
+package dev.baseio.composeplayground.ui.animations.copyfile
+
+import androidx.compose.animation.core.FastOutLinearInEasing
+import androidx.compose.animation.core.LinearOutSlowInEasing
+import androidx.compose.animation.core.RepeatMode.Restart
+import androidx.compose.animation.core.animateFloat
+import androidx.compose.animation.core.infiniteRepeatable
+import androidx.compose.animation.core.keyframes
+import androidx.compose.animation.core.rememberInfiniteTransition
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.material.Surface
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.layoutId
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.constraintlayout.compose.ExperimentalMotionApi
+import androidx.constraintlayout.compose.MotionLayout
+import androidx.constraintlayout.compose.MotionLayoutDebugFlags
+import androidx.constraintlayout.compose.MotionScene
+import dev.baseio.composeplayground.R.drawable
+import dev.baseio.composeplayground.contributors.PushpalRoy
+import dev.baseio.composeplayground.ui.theme.Typography
+import java.util.EnumSet
+
+// Inspiration: https://github.com/amosgyamfi/swiftui-animation-library/blob/master/C/copying_files.gif
+@OptIn(ExperimentalMotionApi::class)
+@Preview(group = "Copy File")
+@Composable
+fun CopyFile() {
+
+ val infiniteTransition = rememberInfiniteTransition()
+ val progressA by infiniteTransition.animateFloat(
+ initialValue = 0f,
+ targetValue = 1f,
+ animationSpec = infiniteRepeatable(
+ animation = keyframes {
+ delayMillis = 100
+ durationMillis = 1800
+ 0.0f at 0 with LinearOutSlowInEasing
+ 0.3f at 600 with FastOutLinearInEasing
+ 1f at 1800 with LinearOutSlowInEasing
+ },
+ repeatMode = Restart
+ )
+ )
+ val progressB by infiniteTransition.animateFloat(
+ initialValue = 0f,
+ targetValue = 1f,
+ animationSpec = infiniteRepeatable(
+ animation = keyframes {
+ delayMillis = 500
+ durationMillis = 2000
+ 0.0f at 0 with LinearOutSlowInEasing
+ 0.4f at 800 with FastOutLinearInEasing
+ 1f at 2000 with LinearOutSlowInEasing
+ },
+ repeatMode = Restart
+ )
+ )
+
+ val progressC by infiniteTransition.animateFloat(
+ initialValue = 0f,
+ targetValue = 1f,
+ animationSpec = infiniteRepeatable(
+ animation = keyframes {
+ delayMillis = 1000
+ durationMillis = 2400
+ 0.0f at 0 with LinearOutSlowInEasing
+ 0.5f at 1000 with FastOutLinearInEasing
+ 1f at 2400 with LinearOutSlowInEasing
+ },
+ repeatMode = Restart
+ )
+ )
+
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(Color(0xFF322F36)),
+ verticalArrangement = Arrangement.Center,
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Text(
+ modifier = Modifier.wrapContentHeight(),
+ text = "Copying files, wait...",
+ style = Typography.subtitle1.copy(color = Color.White),
+ )
+ Surface(
+ modifier = Modifier
+ .wrapContentSize()
+ .padding(bottom = 150.dp)
+ ) {
+ MotionLayout(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(400.dp)
+ .background(Color(0xFF322F36)),
+ motionScene = MotionScene(
+ """{
+ ConstraintSets: {
+ start: {
+ a: {
+ width: 30,
+ height: 30,
+ start: ['parent', 'start', 36],
+ bottom: ['parent', 'bottom', 24]
+ },
+ folder_shared: {
+ width: 50,
+ height: 50,
+ start: ['parent', 'start', 32],
+ bottom: ['parent', 'bottom', 16]
+ },
+ folder: {
+ width: 50,
+ height: 50,
+ end: ['parent', 'end',32],
+ bottom: ['parent', 'bottom', 16]
+ }
+ },
+ end: {
+ a: {
+ width: 25,
+ height: 25,
+ rotationZ: 165,
+ end: ['parent', 'end', 36],
+ bottom: ['parent', 'bottom', 24]
+ },
+ folder_shared: {
+ width: 50,
+ height: 50,
+ start: ['parent', 'start', 32],
+ bottom: ['parent', 'bottom', 16]
+ },
+ folder: {
+ width: 50,
+ height: 50,
+ end: ['parent', 'end',32],
+ bottom: ['parent', 'bottom', 16]
+ }
+ }
+ },
+ Transitions: {
+ default: {
+ from: 'start',
+ to: 'end',
+ pathMotionArc: 'a',
+ KeyFrames: {
+ KeyPositions: [
+ {
+ target: ['a'],
+ frames: [5, 50, 95],
+ percentY: [0.8, 0.5, 0.8],
+ type: 'parentRelative'
+ }
+ ],
+ KeyCycles: [
+ {
+ target: ['a'],
+ frames: [0, 50, 100],
+ period: [0 , 0 , 5],
+ rotationX: [0, 45, 45],
+ rotationY: [0, 45, 45],
+ }
+ ]
+ }
+ }
+ }
+ }"""
+ ),
+ debug = EnumSet.of(MotionLayoutDebugFlags.NONE),
+ progress = progressA
+ ) {
+ Image(
+ painter = painterResource(id = drawable.ic_send),
+ contentDescription = null,
+ modifier = Modifier.layoutId("a")
+ )
+ Image(
+ painter = painterResource(id = drawable.ic_folder_shared),
+ contentDescription = null,
+ modifier = Modifier.layoutId("folder_shared")
+ )
+ Image(
+ painter = painterResource(id = drawable.ic_folder),
+ contentDescription = null,
+ modifier = Modifier.layoutId("folder")
+ )
+ }
+
+ MotionLayout(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(400.dp),
+ motionScene = MotionScene(
+ """{
+ ConstraintSets: {
+ start: {
+ b: {
+ width: 30,
+ height: 30,
+ start: ['parent', 'start', 36],
+ bottom: ['parent', 'bottom', 24]
+ }
+ },
+ end: {
+ b: {
+ width: 25,
+ height: 25,
+ rotationZ: 165,
+ end: ['parent', 'end',36],
+ bottom: ['parent', 'bottom', 24]
+ }
+ }
+ },
+ Transitions: {
+ default: {
+ from: 'start',
+ to: 'end',
+ pathMotionArc: 'a',
+ KeyFrames: {
+ KeyPositions: [
+ {
+ target: ['b'],
+ frames: [5, 50, 95],
+ percentY: [0.8, 0.5, 0.8],
+ type: 'parentRelative'
+ }
+ ],
+ KeyCycles: [
+ {
+ target: ['b'],
+ frames: [0, 50, 100],
+ period: [0 , 0 , 5],
+ rotationX: [0, 45, 45],
+ rotationY: [0, 45, 45],
+ }
+ ]
+ }
+ }
+ }
+ }"""
+ ),
+ debug = EnumSet.of(MotionLayoutDebugFlags.NONE),
+ progress = progressB
+ ) {
+ Image(
+ painter = painterResource(id = drawable.ic_send),
+ contentDescription = null,
+ modifier = Modifier.layoutId("b")
+ )
+ }
+
+ MotionLayout(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(400.dp),
+ motionScene = MotionScene(
+ """{
+ ConstraintSets: {
+ start: {
+ c: {
+ width: 30,
+ height: 30,
+ start: ['parent', 'start', 36],
+ bottom: ['parent', 'bottom', 24]
+ }
+ },
+ end: {
+ c: {
+ width: 25,
+ height: 25,
+ rotationZ: 165,
+ end: ['parent', 'end',36],
+ bottom: ['parent', 'bottom', 24]
+ }
+ }
+ },
+ Transitions: {
+ default: {
+ from: 'start',
+ to: 'end',
+ pathMotionArc: 'a',
+ KeyFrames: {
+ KeyPositions: [
+ {
+ target: ['c'],
+ frames: [5, 50, 95],
+ percentY: [0.8, 0.5, 0.8],
+ type: 'parentRelative'
+ }
+ ],
+ KeyCycles: [
+ {
+ target: ['c'],
+ frames: [0, 50, 100],
+ period: [0 , 0 , 5],
+ rotationX: [0, 45, 45],
+ rotationY: [0, 45, 45],
+ }
+ ]
+ }
+ }
+ }
+ }"""
+ ),
+ debug = EnumSet.of(MotionLayoutDebugFlags.NONE),
+ progress = progressC
+ ) {
+ Image(
+ painter = painterResource(id = drawable.ic_send),
+ contentDescription = null,
+ modifier = Modifier.layoutId("c")
+ )
+ }
+ }
+ PushpalRoy()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/dev/baseio/composeplayground/ui/animations/copyfile/CopyFile2.kt b/app/src/main/java/dev/baseio/composeplayground/ui/animations/copyfile/CopyFile2.kt
new file mode 100644
index 0000000..3772939
--- /dev/null
+++ b/app/src/main/java/dev/baseio/composeplayground/ui/animations/copyfile/CopyFile2.kt
@@ -0,0 +1,162 @@
+package dev.baseio.composeplayground.ui.animations.copyfile
+
+import androidx.compose.animation.core.FastOutLinearInEasing
+import androidx.compose.animation.core.RepeatMode.Restart
+import androidx.compose.animation.core.animateFloat
+import androidx.compose.animation.core.infiniteRepeatable
+import androidx.compose.animation.core.rememberInfiniteTransition
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.material.Surface
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.layoutId
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.constraintlayout.compose.ExperimentalMotionApi
+import androidx.constraintlayout.compose.MotionLayout
+import androidx.constraintlayout.compose.MotionLayoutDebugFlags
+import androidx.constraintlayout.compose.MotionScene
+import dev.baseio.composeplayground.R.drawable
+import dev.baseio.composeplayground.contributors.PushpalRoy
+import dev.baseio.composeplayground.ui.theme.Typography
+import java.util.EnumSet
+
+@OptIn(ExperimentalMotionApi::class)
+@Preview(group = "Copy File 2")
+@Composable
+fun CopyFile2() {
+
+ val infiniteTransition = rememberInfiniteTransition()
+ val progressA by infiniteTransition.animateFloat(
+ initialValue = 0f,
+ targetValue = 1f,
+ animationSpec = infiniteRepeatable(
+ animation = tween(delayMillis = 200, durationMillis = 2800, easing = FastOutLinearInEasing),
+ repeatMode = Restart
+ )
+ )
+
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(Color(0xFF322F36)),
+ verticalArrangement = Arrangement.Center,
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Text(
+ modifier = Modifier.wrapContentHeight(),
+ text = "Copying files, wait...",
+ style = Typography.subtitle1.copy(color = Color.White),
+ )
+ Surface(
+ modifier = Modifier
+ .wrapContentSize()
+ .padding(bottom = 150.dp)
+ ) {
+ MotionLayout(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(400.dp)
+ .background(Color(0xFF322F36)),
+ motionScene = MotionScene(
+ """{
+ ConstraintSets: {
+ start: {
+ a: {
+ width: 40,
+ height: 40,
+ start: ['parent', 'start', 36],
+ bottom: ['parent', 'bottom', 24]
+ },
+ folder_shared: {
+ width: 50,
+ height: 50,
+ start: ['parent', 'start', 32],
+ bottom: ['parent', 'bottom', 16]
+ },
+ folder: {
+ width: 50,
+ height: 50,
+ end: ['parent', 'end',32],
+ bottom: ['parent', 'bottom', 16]
+ }
+ },
+ end: {
+ a: {
+ width: 40,
+ height: 40,
+ rotationY: 185,
+ end: ['parent', 'end', 36],
+ bottom: ['parent', 'bottom', 24]
+ },
+ folder_shared: {
+ width: 50,
+ height: 50,
+ start: ['parent', 'start', 32],
+ bottom: ['parent', 'bottom', 16]
+ },
+ folder: {
+ width: 50,
+ height: 50,
+ end: ['parent', 'end',32],
+ bottom: ['parent', 'bottom', 16]
+ }
+ }
+ },
+ Transitions: {
+ default: {
+ from: 'start',
+ to: 'end',
+ pathMotionArc: 'a',
+ KeyFrames: {
+ KeyPositions: [
+ {
+ target: ['a'],
+ frames: [1, 10, 50, 99, 99],
+ percentY: [0.9, 0.6, 0.6, 0.6, 0.9],
+ type: 'parentRelative'
+ }
+ ]
+ }
+ }
+ }
+ }"""
+ ),
+ debug = EnumSet.of(MotionLayoutDebugFlags.SHOW_ALL),
+ progress = progressA
+ ) {
+ Image(
+ painter = painterResource(id = drawable.ic_file),
+ contentDescription = null,
+ modifier = Modifier.layoutId("a")
+ )
+ Image(
+ painter = painterResource(id = drawable.ic_folder_shared),
+ contentDescription = null,
+ modifier = Modifier.layoutId("folder_shared")
+ )
+ Image(
+ painter = painterResource(id = drawable.ic_folder),
+ contentDescription = null,
+ modifier = Modifier.layoutId("folder")
+ )
+ }
+ }
+ PushpalRoy()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable-hdpi/ic_send.png b/app/src/main/res/drawable-hdpi/ic_send.png
new file mode 100644
index 0000000..2658e8c
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_send.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_send.png b/app/src/main/res/drawable-mdpi/ic_send.png
new file mode 100644
index 0000000..e161f2a
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_send.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_send.png b/app/src/main/res/drawable-xhdpi/ic_send.png
new file mode 100644
index 0000000..5113d38
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_send.png differ
diff --git a/app/src/main/res/drawable/ic_file.xml b/app/src/main/res/drawable/ic_file.xml
new file mode 100644
index 0000000..eae0bfe
--- /dev/null
+++ b/app/src/main/res/drawable/ic_file.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_folder.xml b/app/src/main/res/drawable/ic_folder.xml
new file mode 100644
index 0000000..0a51188
--- /dev/null
+++ b/app/src/main/res/drawable/ic_folder.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_folder_shared.xml b/app/src/main/res/drawable/ic_folder_shared.xml
new file mode 100644
index 0000000..07e4f50
--- /dev/null
+++ b/app/src/main/res/drawable/ic_folder_shared.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a144b92..0afd057 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -2,6 +2,8 @@
Compose Playground
Anmol Verma
anmol.verma@mutualmobile.com\nanmol.verma4@gmail.com
+ Pushpal Roy
+ pushpal.roy@mutualmobile.com\npushplaroy2007@gmail.com
LOADING
\ No newline at end of file