diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..aa724b7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..25a652f
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+Tiktok Video Downloader (Without Watermark)
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..b589d56
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 0000000..ae388c2
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..83915d7
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
new file mode 100644
index 0000000..fdf8d99
--- /dev/null
+++ b/.idea/kotlinc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..8978d23
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/app/.idea/.gitignore b/app/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/app/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/app/.idea/.name b/app/.idea/.name
new file mode 100644
index 0000000..25a652f
--- /dev/null
+++ b/app/.idea/.name
@@ -0,0 +1 @@
+Tiktok Video Downloader (Without Watermark)
\ No newline at end of file
diff --git a/app/.idea/compiler.xml b/app/.idea/compiler.xml
new file mode 100644
index 0000000..b589d56
--- /dev/null
+++ b/app/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/.idea/gradle.xml b/app/.idea/gradle.xml
new file mode 100644
index 0000000..93fb31b
--- /dev/null
+++ b/app/.idea/gradle.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/.idea/kotlinc.xml b/app/.idea/kotlinc.xml
new file mode 100644
index 0000000..fdf8d99
--- /dev/null
+++ b/app/.idea/kotlinc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/.idea/misc.xml b/app/.idea/misc.xml
new file mode 100644
index 0000000..8978d23
--- /dev/null
+++ b/app/.idea/misc.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/.idea/navEditor.xml b/app/.idea/navEditor.xml
new file mode 100644
index 0000000..b6524c1
--- /dev/null
+++ b/app/.idea/navEditor.xml
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/.idea/vcs.xml b/app/.idea/vcs.xml
new file mode 100644
index 0000000..6c0b863
--- /dev/null
+++ b/app/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
new file mode 100644
index 0000000..b498419
--- /dev/null
+++ b/app/build.gradle.kts
@@ -0,0 +1,83 @@
+plugins {
+ id("com.android.application")
+ id("org.jetbrains.kotlin.android")
+ id("kotlin-kapt")
+}
+
+android {
+ namespace = "com.example.tiktokvideodownloaderwithoutwatermark"
+ compileSdk = 34
+
+ defaultConfig {
+ applicationId = "com.example.tiktokvideodownloaderwithoutwatermark"
+ minSdk = 24
+ targetSdk = 34
+ versionCode = 1
+ versionName = "1.0"
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = true
+ isShrinkResources = true
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+ kotlinOptions {
+ jvmTarget = "17"
+ }
+
+ buildFeatures {
+ viewBinding = true
+ }
+
+ tasks.register("wrapper") {
+ gradleVersion = "7.2"
+ }
+
+ tasks.register("prepareKotlinBuildScriptModel"){}
+
+}
+
+dependencies {
+
+ implementation("androidx.core:core-ktx:1.12.0")
+ implementation("androidx.appcompat:appcompat:1.6.1")
+ implementation("com.google.android.material:material:1.10.0")
+ implementation("androidx.constraintlayout:constraintlayout:2.1.4")
+ testImplementation("junit:junit:4.13.2")
+ androidTestImplementation("androidx.test.ext:junit:1.1.5")
+ androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
+
+ //SDP TO SHOW SAME VIEW GROUP SIZES ON ALL SCREENS
+ implementation ("com.intuit.sdp:sdp-android:1.1.0")
+
+ //NAVIGATION TO NAVIGATION FROM ONE DESTINATION TO OTHER
+ implementation ("androidx.navigation:navigation-fragment-ktx:2.7.5")
+ implementation ("androidx.navigation:navigation-ui-ktx:2.7.5")
+
+ //SSP FOR TO SET SAME TEXT SIZE ON ALL SCREEN SIZES
+ implementation ("com.intuit.ssp:ssp-android:1.1.0")
+
+ //RETROFIT FOR NETWORK CALLS
+ implementation("com.squareup.retrofit2:retrofit:2.9.0")
+ implementation("com.squareup.retrofit2:converter-gson:2.9.0")
+
+ //GLIDE LIBRARY FOR IMAGE CACHING
+ implementation ("com.github.bumptech.glide:glide:4.16.0")
+ annotationProcessor ("com.github.bumptech.glide:compiler:4.15.1")
+
+ //LOTTIE FILES TO SHOW ANIMATION
+ implementation ("com.airbnb.android:lottie:6.2.0")
+
+
+}
\ No newline at end of file
diff --git a/app/gradle/wrapper/gradle-wrapper.jar b/app/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..7f93135
Binary files /dev/null and b/app/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/app/gradle/wrapper/gradle-wrapper.properties b/app/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..722117b
--- /dev/null
+++ b/app/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/app/gradlew b/app/gradlew
new file mode 100644
index 0000000..1aa94a4
--- /dev/null
+++ b/app/gradlew
@@ -0,0 +1,249 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/app/gradlew.bat b/app/gradlew.bat
new file mode 100644
index 0000000..93e3f59
--- /dev/null
+++ b/app/gradlew.bat
@@ -0,0 +1,92 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..051ab4d
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/adapters/DownloadAdapters.kt b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/adapters/DownloadAdapters.kt
new file mode 100644
index 0000000..35be319
--- /dev/null
+++ b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/adapters/DownloadAdapters.kt
@@ -0,0 +1,96 @@
+package com.example.tiktokvideodownloaderwithoutwatermark.adapters
+
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.util.Log
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.MenuItem
+import android.view.View
+import android.view.ViewGroup
+import android.widget.PopupMenu
+import android.widget.Toast
+import androidx.recyclerview.widget.RecyclerView
+import com.bumptech.glide.Glide
+import com.example.tiktokvideodownloaderwithoutwatermark.R
+import com.example.tiktokvideodownloaderwithoutwatermark.databinding.VideoItemsBinding
+import com.example.tiktokvideodownloaderwithoutwatermark.models.MediaModel
+import com.example.tiktokvideodownloaderwithoutwatermark.utils.Utils
+import com.example.tiktokvideodownloaderwithoutwatermark.utils.Utils.showAudio
+import com.example.tiktokvideodownloaderwithoutwatermark.utils.Utils.showVideo
+import okhttp3.internal.Util
+import java.io.File
+
+class DownloadAdapters : RecyclerView.Adapter() {
+ private var downloadList: ArrayList = ArrayList()
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DownloadViewHolder {
+ val binding =
+ VideoItemsBinding.inflate(LayoutInflater.from(parent.context), parent, false)
+ return DownloadViewHolder(binding)
+ }
+
+ override fun getItemCount(): Int {
+ return downloadList.size
+ }
+
+ override fun onBindViewHolder(holder: DownloadViewHolder, position: Int) {
+ holder.bind(downloadList[position])
+ }
+
+ class DownloadViewHolder(private val binding: VideoItemsBinding) :
+ RecyclerView.ViewHolder(binding.root) {
+ fun bind(item: MediaModel) {
+ Glide.with(binding.root.context).load(item.uri)
+ .placeholder(R.drawable.music).into(binding.tvImgMedia)
+ binding.tvVideoName.text = item.name
+ binding.tvVideoName.isSelected = true
+ (item.size + " - " + item.duration).also { binding.tvVideoDetails.text = it }
+
+ binding.imgMore.setOnClickListener {
+ showPopupMenu(binding.imgMore, binding.root.context, item.uri)
+ }
+
+ }
+
+ private fun showPopupMenu(view: View, context: Context, uri: Uri) {
+ val popupMenu = PopupMenu(context, view, Gravity.START)
+ popupMenu.menuInflater.inflate(R.menu.more_menu, popupMenu.menu)
+ val isVideo = Utils.isVideoFile(context, uri)
+
+ popupMenu.setOnMenuItemClickListener { item: MenuItem ->
+ when (item.itemId) {
+ R.id.action_share -> {
+ if (isVideo) {
+ Utils.shareVideo(context, uri)
+ } else {
+ Utils.shareAudio(context, uri)
+ }
+ true
+ }
+
+ R.id.action_view -> {
+ if (isVideo) {
+ showVideo(uri, context)
+ } else {
+ showAudio(uri, context)
+ }
+ true
+ }
+
+ else -> false
+ }
+ }
+
+ popupMenu.show()
+ }
+ }
+
+ fun submitList(list: ArrayList) {
+ this.downloadList = list
+ notifyDataSetChanged()
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/adapters/FolderAdapter.kt b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/adapters/FolderAdapter.kt
new file mode 100644
index 0000000..7579f98
--- /dev/null
+++ b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/adapters/FolderAdapter.kt
@@ -0,0 +1,53 @@
+package com.example.tiktokvideodownloaderwithoutwatermark.adapters
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.example.tiktokvideodownloaderwithoutwatermark.databinding.ListFoldersBinding
+import com.example.tiktokvideodownloaderwithoutwatermark.models.folderModel
+
+class FolderAdapter : RecyclerView.Adapter() {
+
+ private var downloadList: ArrayList = ArrayList()
+ private var listener: OnClickListener? = null
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FolderViewHolder {
+ val binding = ListFoldersBinding.inflate(LayoutInflater.from(parent.context), parent, false)
+ return FolderViewHolder(binding)
+ }
+
+ override fun getItemCount(): Int {
+ return downloadList.size
+ }
+
+ override fun onBindViewHolder(holder: FolderViewHolder, position: Int) {
+ holder.bind(downloadList[position])
+ holder.cdMain.setOnClickListener {
+ listener?.onItemClick(downloadList[position])
+ }
+
+ }
+
+ class FolderViewHolder(private val binding: ListFoldersBinding) :
+ RecyclerView.ViewHolder(binding.root) {
+ val cdMain = binding.cdMain
+ fun bind(item: folderModel) {
+ binding.tvFolderName.text = item.name
+ binding.tvNoOfItems.text = "(${item.noOfItems})"
+ }
+ }
+
+ fun submitList(list: ArrayList) {
+ this.downloadList = list
+ notifyDataSetChanged()
+ }
+
+ interface OnClickListener {
+ fun onItemClick(item: folderModel)
+ }
+
+ fun setOnClickListener(listener: OnClickListener) {
+ this.listener = listener
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/app/application.kt b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/app/application.kt
new file mode 100644
index 0000000..4b4c6a5
--- /dev/null
+++ b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/app/application.kt
@@ -0,0 +1,9 @@
+package com.example.tiktokvideodownloaderwithoutwatermark.app
+
+import android.app.Application
+
+class application: Application() {
+ override fun onCreate() {
+ super.onCreate()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/data/remote/repository/TiktokRepo.kt b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/data/remote/repository/TiktokRepo.kt
new file mode 100644
index 0000000..cf48359
--- /dev/null
+++ b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/data/remote/repository/TiktokRepo.kt
@@ -0,0 +1,34 @@
+package com.example.tiktokvideodownloaderwithoutwatermark.data.remote.repository
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import java.net.SocketTimeoutException
+
+class TiktokRepo {
+ private val expandedUrlLiveData = MutableLiveData()
+ fun getExpandedUrlLiveData(): LiveData {
+ return expandedUrlLiveData
+ }
+
+ suspend fun expandShortenedUrl(shortenedUrl: String) = withContext(Dispatchers.IO) {
+ try {
+ val client = OkHttpClient()
+ val request = Request.Builder()
+ .url(shortenedUrl)
+ .build()
+
+ val response = client.newCall(request).execute()
+ val expandedUrl = response.request().url().toString()
+ expandedUrlLiveData.postValue(expandedUrl)
+ } catch (e: SocketTimeoutException) {
+ expandedUrlLiveData.postValue("Timeout occurred: ${e.message}")
+ } catch (e: Exception) {
+ expandedUrlLiveData.postValue("Error: ${e.message}")
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/data/remote/viewModel/TiktokViewModel.kt b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/data/remote/viewModel/TiktokViewModel.kt
new file mode 100644
index 0000000..928e550
--- /dev/null
+++ b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/data/remote/viewModel/TiktokViewModel.kt
@@ -0,0 +1,230 @@
+package com.example.tiktokvideodownloaderwithoutwatermark.data.remote.viewModel
+
+import android.annotation.SuppressLint
+import android.app.AlertDialog
+import android.app.DownloadManager
+import android.content.ContentUris
+import android.content.ContentValues.TAG
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.os.Environment
+import android.provider.MediaStore
+import android.provider.Settings
+import android.util.Log
+import android.widget.Toast
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.example.tiktokvideodownloaderwithoutwatermark.data.remote.repository.TiktokRepo
+import com.example.tiktokvideodownloaderwithoutwatermark.models.MediaModel
+import com.example.tiktokvideodownloaderwithoutwatermark.models.folderModel
+import com.example.tiktokvideodownloaderwithoutwatermark.utils.Utils
+import com.example.tiktokvideodownloaderwithoutwatermark.utils.Utils.AUDIOS
+import com.example.tiktokvideodownloaderwithoutwatermark.utils.Utils.VIDEOS
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.io.File
+
+
+class TiktokViewModel : ViewModel() {
+ private val tiktokRepo: TiktokRepo = TiktokRepo()
+
+ private val expandedUrlLiveData = tiktokRepo.getExpandedUrlLiveData()
+ fun getExpandedUrlLiveData(): LiveData {
+ return expandedUrlLiveData
+ }
+
+ fun expandShortenedUrl(shortenedUrl: String) {
+ viewModelScope.launch {
+ tiktokRepo.expandShortenedUrl(shortenedUrl)
+ }
+ }
+
+ fun extractVideoIdFromUrl(url: String): String? {
+ val pattern = Regex("/video/(\\d+)")
+ val matchResult = pattern.find(url)
+ return matchResult?.groupValues?.getOrNull(1)
+ }
+
+ fun downloadVideo(filename: String, downloadUrlOfVideo: String, context: Context) {
+ try {
+ if (!VIDEOS.exists()) {
+ VIDEOS.mkdirs()
+ }
+
+ val dm = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
+ val downloadUri = Uri.parse(downloadUrlOfVideo)
+ val request = DownloadManager.Request(downloadUri)
+ request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE)
+ .setAllowedOverRoaming(false)
+ .setTitle(filename)
+ .setMimeType("video/*")
+ .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
+ .setDestinationUri(Uri.fromFile(File(VIDEOS, "$filename")))
+
+ dm.enqueue(request)
+
+ Toast.makeText(context, "Download started!", Toast.LENGTH_SHORT).show()
+ } catch (e: Exception) {
+ Toast.makeText(context, "Download failed! ${e.message}", Toast.LENGTH_SHORT).show()
+ }
+ }
+
+
+ fun downloadAudio(filename: String, downloadUrlOfVideo: String, context: Context) {
+ try {
+ if (!AUDIOS.exists()) {
+ AUDIOS.mkdirs()
+ }
+
+ val dm = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
+ val downloadUri = Uri.parse(downloadUrlOfVideo)
+ val request = DownloadManager.Request(downloadUri)
+ request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE)
+ .setAllowedOverRoaming(false)
+ .setTitle(filename)
+ .setMimeType("audio/*")
+ .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
+ .setDestinationUri(Uri.fromFile(File(AUDIOS, "$filename")))
+
+ dm.enqueue(request)
+
+ Toast.makeText(context, "Download started!", Toast.LENGTH_SHORT).show()
+ } catch (e: Exception) {
+ Toast.makeText(context, "Download failed! ${e.message}", Toast.LENGTH_SHORT).show()
+ }
+ }
+
+
+ fun showAlertDialog(heading: String, subHeading: String, context: Context) {
+ AlertDialog.Builder(context)
+ .setTitle(heading)
+ .setMessage(subHeading)
+ .setPositiveButton("OK") { dialog, _ ->
+ dialog.dismiss()
+ val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
+ val uri = Uri.fromParts("package", context.packageName, null)
+ intent.data = uri
+ context.startActivity(intent)
+ }
+ .setNegativeButton("Cancel") { dialog, _ ->
+ dialog.dismiss()
+ }
+ .show()
+ }
+
+
+ suspend fun getVideosFromFolder(context: Context, folderPath: String): ArrayList = withContext(Dispatchers.IO) {
+ val videoList: ArrayList = ArrayList()
+ val projection = arrayOf(
+ MediaStore.Video.Media._ID,
+ MediaStore.Video.Media.DISPLAY_NAME,
+ MediaStore.Video.Media.DURATION,
+ MediaStore.Video.Media.SIZE
+ )
+
+ val selection = "${MediaStore.Video.Media.DATA} like ?"
+ val selectionArgs = arrayOf("$folderPath%")
+
+ val sortOrder = "${MediaStore.Video.Media.DATE_MODIFIED} DESC"
+
+ val queryUri: Uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
+
+ context.contentResolver.query(queryUri, projection, selection, selectionArgs, sortOrder)
+ ?.use { cursor ->
+ while (cursor.moveToNext()) {
+ val videoId = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID))
+ val displayName = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME))
+ val duration = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION))
+ val size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE))
+
+ val contentUri: Uri = ContentUris.withAppendedId(
+ MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
+ videoId
+ )
+ videoList.add(MediaModel(displayName, contentUri, formatDuration(duration), formatSize(size)))
+ }
+ }
+ return@withContext videoList
+ }
+
+ suspend fun getAudiosFromFolder(context: Context, folderPath: String): ArrayList = withContext(Dispatchers.IO) {
+ val audioList: ArrayList = ArrayList()
+ val projection = arrayOf(
+ MediaStore.Audio.Media._ID,
+ MediaStore.Audio.Media.DISPLAY_NAME,
+ MediaStore.Audio.Media.DURATION,
+ MediaStore.Audio.Media.SIZE
+ )
+
+ val selection = "${MediaStore.Audio.Media.DATA} like ?"
+ val selectionArgs = arrayOf("$folderPath%")
+
+ val sortOrder = "${MediaStore.Audio.Media.DATE_MODIFIED} DESC"
+
+ val queryUri: Uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
+
+ context.contentResolver.query(queryUri, projection, selection, selectionArgs, sortOrder)
+ ?.use { cursor ->
+ while (cursor.moveToNext()) {
+ val videoId = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID))
+ val displayName = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME))
+ val duration = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION))
+ val size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE))
+
+ val contentUri: Uri = ContentUris.withAppendedId(
+ MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
+ videoId
+ )
+ audioList.add(MediaModel(displayName, contentUri, formatDuration(duration), formatSize(size)))
+ }
+ }
+ return@withContext audioList
+ }
+
+
+
+ private fun formatSize(size: Long): String {
+ val fileSizeInKB = size / 1024
+ val fileSizeInMB = fileSizeInKB / 1024
+
+ return if (fileSizeInMB > 0) {
+ String.format("%d MB", fileSizeInMB)
+ } else {
+ String.format("%d KB", fileSizeInKB)
+ }
+ }
+
+ private fun formatDuration(duration: Long): String {
+ val seconds = duration / 1000
+ val minutes = seconds / 60
+ val remainingSeconds = seconds % 60
+
+ return String.format("%02d:%02d", minutes, remainingSeconds)
+ }
+
+
+ suspend fun getFolderInfo(): ArrayList = withContext(Dispatchers.IO) {
+ val folderList: ArrayList = ArrayList()
+ if (Utils.TIKTOK_DOWNLOAD_PATH.exists() && Utils.TIKTOK_DOWNLOAD_PATH.isDirectory) {
+ val videosFolder = Utils.TIKTOK_DOWNLOAD_PATH.resolve("VIDEOS")
+ val videosCount = getMediaCount(videosFolder)
+ folderList.add(folderModel(videosFolder.name, videosCount))
+
+ val audiosFolder = Utils.TIKTOK_DOWNLOAD_PATH.resolve("AUDIOS")
+ val audiosCount = getMediaCount(audiosFolder)
+ folderList.add(folderModel(audiosFolder.name, audiosCount))
+ } else {
+ Log.e("NotFound", "TikTok folder not found.")
+ }
+ return@withContext folderList
+ }
+
+ private fun getMediaCount(folder: File): Int {
+ return folder.listFiles { file -> file.isFile }?.size ?: 0
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/models/MediaModel.kt b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/models/MediaModel.kt
new file mode 100644
index 0000000..a9889b2
--- /dev/null
+++ b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/models/MediaModel.kt
@@ -0,0 +1,5 @@
+package com.example.tiktokvideodownloaderwithoutwatermark.models
+
+import android.net.Uri
+
+data class MediaModel(val name: String, val uri: Uri, val duration: String, val size: String)
diff --git a/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/models/folderModel.kt b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/models/folderModel.kt
new file mode 100644
index 0000000..c57294d
--- /dev/null
+++ b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/models/folderModel.kt
@@ -0,0 +1,3 @@
+package com.example.tiktokvideodownloaderwithoutwatermark.models
+
+data class folderModel(val name: String, val noOfItems: Int)
diff --git a/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/ui/activities/MainActivity.kt b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/ui/activities/MainActivity.kt
new file mode 100644
index 0000000..1b5d107
--- /dev/null
+++ b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/ui/activities/MainActivity.kt
@@ -0,0 +1,18 @@
+package com.example.tiktokvideodownloaderwithoutwatermark.ui.activities
+
+import androidx.appcompat.app.AppCompatActivity
+import android.os.Bundle
+import androidx.navigation.findNavController
+import androidx.navigation.ui.setupWithNavController
+import com.example.tiktokvideodownloaderwithoutwatermark.R
+import com.google.android.material.bottomnavigation.BottomNavigationView
+
+class MainActivity : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+ val navController = this.findNavController(R.id.nav_host_fragment)
+ val navView: BottomNavigationView = findViewById(R.id.bottom_nav_view)
+ navView.setupWithNavController(navController)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/ui/fragments/AppSettings.kt b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/ui/fragments/AppSettings.kt
new file mode 100644
index 0000000..2d57422
--- /dev/null
+++ b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/ui/fragments/AppSettings.kt
@@ -0,0 +1,85 @@
+package com.example.tiktokvideodownloaderwithoutwatermark.ui.fragments
+
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.activityViewModels
+import androidx.navigation.fragment.findNavController
+import com.example.tiktokvideodownloaderwithoutwatermark.R
+import com.example.tiktokvideodownloaderwithoutwatermark.data.remote.viewModel.TiktokViewModel
+import com.example.tiktokvideodownloaderwithoutwatermark.databinding.FragmentAppSettingsBinding
+import com.example.tiktokvideodownloaderwithoutwatermark.models.folderModel
+import com.example.tiktokvideodownloaderwithoutwatermark.utils.Utils
+
+
+class AppSettings : Fragment(){
+ private var _binding: FragmentAppSettingsBinding? = null
+ private val binding get() = _binding!!
+ private val viewModel: TiktokViewModel by activityViewModels()
+ private val list: ArrayList = ArrayList()
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ _binding = FragmentAppSettingsBinding.inflate(inflater, container, false)
+
+ binding.storagePath.text = Utils.TIKTOK_DOWNLOAD_PATH.absolutePath
+ binding.appVersion.text = "1.0"
+ binding.storagePath.isSelected = true
+
+ binding.cdPrivcyPolicy.setOnClickListener {
+ try {
+ findNavController().navigate(R.id.action_action_settings_to_privacyPolicy)
+ } catch (ex: Exception) {
+ ex.printStackTrace()
+ }
+ }
+
+ binding.cdShare.setOnClickListener { shareAppLink() }
+
+ binding.cdRateUs.setOnClickListener { openPlayStore() }
+
+ return binding.root
+ }
+
+
+ private fun shareAppLink() {
+ val appLink =
+ "https://play.google.com/store/apps/details?id=${requireContext().packageName}"
+ val intent = Intent(Intent.ACTION_SEND)
+ intent.type = "text/plain"
+ intent.putExtra(Intent.EXTRA_TEXT, appLink)
+ startActivity(Intent.createChooser(intent, "Share App Link"))
+ }
+
+ private fun openPlayStore() {
+ val appPackageName = requireActivity().packageName
+ try {
+ startActivity(
+ Intent(
+ Intent.ACTION_VIEW,
+ Uri.parse("market://details?id=$appPackageName")
+ )
+ )
+ } catch (e: android.content.ActivityNotFoundException) {
+ startActivity(
+ Intent(
+ Intent.ACTION_VIEW,
+ Uri.parse("https://play.google.com/store/apps/details?id=$appPackageName")
+ )
+ )
+ }
+ }
+
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/ui/fragments/Download.kt b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/ui/fragments/Download.kt
new file mode 100644
index 0000000..57141b1
--- /dev/null
+++ b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/ui/fragments/Download.kt
@@ -0,0 +1,79 @@
+package com.example.tiktokvideodownloaderwithoutwatermark.ui.fragments
+
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.lifecycleScope
+import androidx.navigation.fragment.findNavController
+import com.example.tiktokvideodownloaderwithoutwatermark.R
+import com.example.tiktokvideodownloaderwithoutwatermark.adapters.FolderAdapter
+import com.example.tiktokvideodownloaderwithoutwatermark.data.remote.viewModel.TiktokViewModel
+import com.example.tiktokvideodownloaderwithoutwatermark.databinding.FragmentDownloadBinding
+import com.example.tiktokvideodownloaderwithoutwatermark.models.folderModel
+import kotlinx.coroutines.launch
+
+class Download : Fragment() {
+ private var _binding: FragmentDownloadBinding? = null
+ private val binding get() = _binding!!
+ private val viewModel: TiktokViewModel by activityViewModels()
+ private lateinit var adapter: FolderAdapter
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ _binding = FragmentDownloadBinding.inflate(inflater, container, false)
+
+ adapter = FolderAdapter()
+ binding.recyclerView.adapter = adapter
+ binding.recyclerView.setHasFixedSize(true)
+
+ lifecycleScope.launch {
+ val list = viewModel.getFolderInfo()
+ if (list.isNotEmpty()) {
+ binding.textView2.visibility = View.GONE
+ adapter.submitList(list)
+ }
+ }
+
+ adapter.setOnClickListener(listener = object : FolderAdapter.OnClickListener {
+ override fun onItemClick(item: folderModel) {
+ try {
+ val bundle = Bundle()
+ when (item.name) {
+ "AUDIOS" -> {
+ bundle.putString("MEDIA", "audio")
+ findNavController().navigate(
+ R.id.action_action_download_to_mediaItems,
+ bundle
+ )
+ }
+
+ "VIDEOS" -> {
+ bundle.putString("MEDIA", "video")
+ findNavController().navigate(
+ R.id.action_action_download_to_mediaItems,
+ bundle
+ )
+ }
+ }
+ } catch (ex: Exception) {
+ ex.printStackTrace()
+ }
+ }
+
+ })
+
+ return binding.root
+ }
+
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/ui/fragments/Home.kt b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/ui/fragments/Home.kt
new file mode 100644
index 0000000..051d409
--- /dev/null
+++ b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/ui/fragments/Home.kt
@@ -0,0 +1,211 @@
+package com.example.tiktokvideodownloaderwithoutwatermark.ui.fragments
+
+import android.Manifest
+import android.app.AlertDialog
+import android.content.Context
+import android.graphics.Color
+import android.graphics.drawable.ColorDrawable
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.Window
+import android.view.inputmethod.InputMethodManager
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.lifecycleScope
+import com.bumptech.glide.Glide
+import com.example.tiktokvideodownloaderwithoutwatermark.R
+import com.example.tiktokvideodownloaderwithoutwatermark.data.remote.viewModel.TiktokViewModel
+import com.example.tiktokvideodownloaderwithoutwatermark.utils.Utils
+import com.example.tiktokvideodownloaderwithoutwatermark.utils.Utils.TIKTOK_DOWNLOAD_PATH
+import com.example.tiktokvideodownloaderwithoutwatermark.databinding.FragmentHomeBinding
+import com.example.tiktokvideodownloaderwithoutwatermark.utils.showToast
+import kotlinx.coroutines.launch
+
+class Home : Fragment() {
+ private var _binding: FragmentHomeBinding? = null
+ private val binding get() = _binding!!
+ private val viewModel: TiktokViewModel by activityViewModels()
+ private var videoId: String? = null
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ _binding = FragmentHomeBinding.inflate(inflater, container, false)
+
+ binding.btnDownload.setOnClickListener {
+ hideKeyboard(binding.root)
+ startReadExternalStoragePermission()
+ }
+
+
+
+ binding.clearText.setOnClickListener {
+ binding.edUrl.setText("")
+ }
+
+
+ binding.btnPaste.setOnClickListener {
+ val copyBoardText = Utils.pasteFromClipboard(requireContext())
+ if (copyBoardText.isNotEmpty()) {
+ binding.edUrl.setText(copyBoardText)
+ } else {
+ binding.edUrl.setText("")
+ }
+ }
+
+
+ binding.cdAudio.setOnClickListener {
+ viewModel.downloadAudio(
+ "Video-$videoId.mp3",
+ "${Utils.DOWNLOAD_AUDIO_LINK}$videoId.mp3",
+ requireContext()
+ )
+ }
+
+ binding.cdOriginalVideo.setOnClickListener {
+ viewModel.downloadVideo(
+ "Video-Original-$videoId.mp4",
+ "${Utils.DOWNLOAD_ORIGINAL_VIDEO_LINK}$videoId.mp4",
+ requireContext()
+ )
+ }
+
+ binding.cdDownloadWithoutWaterMark.setOnClickListener {
+ viewModel.downloadVideo(
+ "Video-WM-$videoId.mp4",
+ "${Utils.DOWNLOAD_VIDEO_WITHOUT_WATERMARK}$videoId.mp4",
+ requireContext()
+ )
+ }
+
+ binding.cdDownloadWithoutWaterMarkHD.setOnClickListener {
+ viewModel.downloadVideo(
+ "Video-WMHD-$videoId.mp4",
+ "${Utils.DOWNLOAD_VIDEO_WITHOUT_WATERMARK_HD}$videoId.mp4",
+ requireContext()
+ )
+ }
+
+
+ binding.downloadAnother.setOnClickListener {
+ binding.cdDownloadOptions.visibility = View.GONE
+ }
+
+
+
+
+ return binding.root
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ }
+
+
+ private fun startReadExternalStoragePermission() {
+ this.requestReadExternalPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
+ }
+
+
+ private val requestReadExternalPermissionLauncher = registerForActivityResult(
+ ActivityResultContracts.RequestPermission()
+ ) { isGranted ->
+ if (isGranted) {
+ startWriteExternalStoragePermission()
+ } else {
+ viewModel.showAlertDialog(
+ getString(R.string.media_permission),
+ getString(R.string.please_allow_media_permission_to_continue),
+ requireContext()
+ )
+ }
+ }
+
+ private fun startWriteExternalStoragePermission() {
+ this.requestWriteExternalPermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ }
+
+ private val requestWriteExternalPermissionLauncher = registerForActivityResult(
+ ActivityResultContracts.RequestPermission()
+ ) { isGranted ->
+ if (isGranted) {
+ if (binding.edUrl.text.toString().isNotEmpty()) {
+ lifecycleScope.launch {
+ if (Utils.isValidUrl(binding.edUrl.text.toString())) {
+
+ val dialogBuilder = AlertDialog.Builder(context)
+ val inflater = requireActivity().layoutInflater
+ val dialogView: View =
+ inflater.inflate(R.layout.fetching_dialog, null, false)
+ dialogBuilder.setView(dialogView)
+ val alertDialog = dialogBuilder.create()
+ alertDialog.setCancelable(false)
+
+
+
+ alertDialog.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
+ alertDialog.window!!.attributes.windowAnimations = R.style.DialogAnimation
+
+
+
+ alertDialog.show()
+ val window: Window? = alertDialog.window
+ window!!.setLayout(
+ ConstraintLayout.LayoutParams.WRAP_CONTENT,
+ ConstraintLayout.LayoutParams.WRAP_CONTENT
+ )
+
+
+
+ viewModel.expandShortenedUrl(binding.edUrl.text.toString())
+ viewModel.getExpandedUrlLiveData()
+ .observe(viewLifecycleOwner) { expandedUrl ->
+ alertDialog.dismiss()
+ if (expandedUrl == "Error:" || expandedUrl == "Timeout occurred:") {
+ showToast(expandedUrl.toString())
+ return@observe
+ } else {
+ videoId = viewModel.extractVideoIdFromUrl(expandedUrl)
+ if (!TIKTOK_DOWNLOAD_PATH.exists()) {
+ TIKTOK_DOWNLOAD_PATH.mkdir()
+ }
+ Glide.with(requireContext())
+ .load("${Utils.SOURCE_IMAGEVIEW}$videoId.webp")
+ .into(binding.srcImage)
+
+ binding.edUrl.setText("")
+ binding.cdDownloadOptions.visibility = View.VISIBLE
+ }
+ }
+
+ } else {
+ showToast("Invalid url, please check again that pasted url is of tiktok video.")
+ }
+ }
+ } else {
+ showToast("url is not valid!")
+ }
+ } else {
+
+ viewModel.showAlertDialog(
+ getString(R.string.media_permission),
+ getString(R.string.please_allow_media_permission_to_continue),
+ requireContext()
+
+ )
+ }
+ }
+
+
+ private fun hideKeyboard(view: View) {
+ val inputMethodManager = requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+ inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/ui/fragments/MediaItems.kt b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/ui/fragments/MediaItems.kt
new file mode 100644
index 0000000..563a920
--- /dev/null
+++ b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/ui/fragments/MediaItems.kt
@@ -0,0 +1,63 @@
+package com.example.tiktokvideodownloaderwithoutwatermark.ui.fragments
+
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import android.view.LayoutInflater
+import android.view.MenuItem
+import android.view.View
+import android.view.ViewGroup
+import android.widget.PopupMenu
+import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.lifecycleScope
+import com.example.tiktokvideodownloaderwithoutwatermark.R
+import com.example.tiktokvideodownloaderwithoutwatermark.adapters.DownloadAdapters
+import com.example.tiktokvideodownloaderwithoutwatermark.data.remote.viewModel.TiktokViewModel
+import com.example.tiktokvideodownloaderwithoutwatermark.databinding.FragmentMediaItemsBinding
+import com.example.tiktokvideodownloaderwithoutwatermark.models.MediaModel
+import com.example.tiktokvideodownloaderwithoutwatermark.utils.Utils
+import kotlinx.coroutines.launch
+
+class MediaItems : Fragment() {
+ private var _binding: FragmentMediaItemsBinding? = null
+ private val binding get() = _binding!!
+ private val viewModel: TiktokViewModel by activityViewModels()
+ private lateinit var adapter: DownloadAdapters
+ private var list: ArrayList = ArrayList()
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ _binding = FragmentMediaItemsBinding.inflate(inflater, container, false)
+
+ val arguments: String? = requireArguments().getString("MEDIA")
+
+ adapter = DownloadAdapters()
+ binding.recyclerView.adapter = adapter
+ binding.recyclerView.setHasFixedSize(true)
+
+ lifecycleScope.launch {
+ when (arguments) {
+ "audio" -> {
+ list =
+ viewModel.getAudiosFromFolder(requireContext(), Utils.AUDIOS.absolutePath)
+ adapter.submitList(list)
+ }
+
+ "video" -> {
+ list =
+ viewModel.getVideosFromFolder(requireContext(), Utils.VIDEOS.absolutePath)
+ adapter.submitList(list)
+ }
+ }
+ }
+
+
+ return binding.root
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/ui/fragments/PrivacyPolicy.kt b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/ui/fragments/PrivacyPolicy.kt
new file mode 100644
index 0000000..104babe
--- /dev/null
+++ b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/ui/fragments/PrivacyPolicy.kt
@@ -0,0 +1,30 @@
+package com.example.tiktokvideodownloaderwithoutwatermark.ui.fragments
+
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.navigation.fragment.findNavController
+import com.example.tiktokvideodownloaderwithoutwatermark.databinding.FragmentPrivacyPolicyBinding
+
+
+class PrivacyPolicy : Fragment() {
+ private var _binding: FragmentPrivacyPolicyBinding? = null
+ private val binding get() = _binding!!
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ _binding = FragmentPrivacyPolicyBinding.inflate(inflater, container, false)
+ binding.textView.setOnClickListener {
+ findNavController().popBackStack()
+ }
+ return binding.root
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/utils/Utils.kt b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/utils/Utils.kt
new file mode 100644
index 0000000..bd8f093
--- /dev/null
+++ b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/utils/Utils.kt
@@ -0,0 +1,129 @@
+package com.example.tiktokvideodownloaderwithoutwatermark.utils
+
+import android.app.Activity
+import android.content.ClipboardManager
+import android.content.ContentResolver
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.os.Environment
+import android.view.View
+import android.view.inputmethod.InputMethodManager
+import android.widget.Toast
+import java.io.File
+import java.net.MalformedURLException
+import java.net.URL
+
+object Utils {
+ val DOWNLOAD_AUDIO_LINK = "https://www.tikwm.com/video/music/"
+ val DOWNLOAD_ORIGINAL_VIDEO_LINK = "https://www.tikwm.com/video/media/wmplay/"
+ val DOWNLOAD_VIDEO_WITHOUT_WATERMARK = "https://www.tikwm.com/video/media/play/"
+ val DOWNLOAD_VIDEO_WITHOUT_WATERMARK_HD = "https://www.tikwm.com/video/media/hdplay/"
+ val SOURCE_IMAGEVIEW = "https://www.tikwm.com/video/cover/"
+
+
+ val TIKTOK_DOWNLOAD_PATH = File(
+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
+ "TIKTOK VIDEO DOWNLOADER"
+ )
+
+ val VIDEOS = File(
+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
+ "TIKTOK VIDEO DOWNLOADER/VIDEOS"
+ )
+
+ val AUDIOS = File(
+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
+ "TIKTOK VIDEO DOWNLOADER/AUDIOS"
+ )
+
+ fun isValidUrl(urlString: String): Boolean {
+ return try {
+ val url = URL(urlString)
+ url.protocol == "http" || url.protocol == "https"
+ true
+ } catch (e: MalformedURLException) {
+ e.printStackTrace()
+ false
+ }
+ }
+
+ fun shareVideo(context: Context, videoUri: Uri) {
+ val shareIntent = Intent(Intent.ACTION_SEND)
+ shareIntent.type = "video/*"
+ shareIntent.putExtra(Intent.EXTRA_STREAM, videoUri)
+ shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ context.startActivity(Intent.createChooser(shareIntent, "Share Video"))
+ }
+
+
+ fun showVideo(uri: Uri, context: Context) {
+ val intent = Intent(Intent.ACTION_VIEW, uri)
+ intent.setDataAndType(uri, "video/*")
+
+ if (intent.resolveActivity(context.packageManager) != null) {
+ context.startActivity(intent)
+ } else {
+ Toast.makeText(context, "No app to handle video playback", Toast.LENGTH_SHORT)
+ .show()
+ }
+ }
+
+ fun showAudio(uri: Uri, context: Context) {
+ val intent = Intent(Intent.ACTION_VIEW, uri)
+ intent.setDataAndType(uri, "audio/*")
+
+ if (intent.resolveActivity(context.packageManager) != null) {
+ context.startActivity(intent)
+ } else {
+ Toast.makeText(context, "No app to handle video playback", Toast.LENGTH_SHORT)
+ .show()
+ }
+ }
+
+ fun shareAudio(context: Context, audioUri: Uri) {
+ val shareIntent = Intent(Intent.ACTION_SEND)
+ shareIntent.type = "audio/*"
+ shareIntent.putExtra(Intent.EXTRA_STREAM, audioUri)
+ shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ context.startActivity(Intent.createChooser(shareIntent, "Share Audio"))
+ }
+
+ fun pasteFromClipboard(context: Context): String {
+ var clipBoardText: String? = null
+ val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
+ if (clipboard.hasPrimaryClip()) {
+ val clip = clipboard.primaryClip
+ val item = clip?.getItemAt(0)
+ clipBoardText = item?.text.toString()
+ }
+ return clipBoardText!!
+ }
+
+
+ fun isVideoFile(context: Context, uri: Uri): Boolean {
+ val mimeType = getMimeType(context, uri)
+ return mimeType?.startsWith("video/") == true
+ }
+
+ fun isAudioFile(context: Context, uri: Uri): Boolean {
+ val mimeType = getMimeType(context, uri)
+ return mimeType?.startsWith("audio/") == true
+ }
+
+ private fun getMimeType(context: Context, uri: Uri): String? {
+ val contentResolver: ContentResolver = context.contentResolver
+ return try {
+ contentResolver.getType(uri)
+ } catch (e: Exception) {
+ null
+ }
+ }
+
+
+ fun Context.hideKeyboard(view: View) {
+ val inputMethodManager = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
+ inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/utils/extension.kt b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/utils/extension.kt
new file mode 100644
index 0000000..8a267a2
--- /dev/null
+++ b/app/src/main/java/com/example/tiktokvideodownloaderwithoutwatermark/utils/extension.kt
@@ -0,0 +1,12 @@
+package com.example.tiktokvideodownloaderwithoutwatermark.utils
+
+import android.view.View
+import android.widget.Toast
+import androidx.fragment.app.Fragment
+
+fun Fragment.showToast(message: String)
+{
+ Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
+}
+
+
diff --git a/app/src/main/res/drawable/baseline_close_24.xml b/app/src/main/res/drawable/baseline_close_24.xml
new file mode 100644
index 0000000..a038f30
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_close_24.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/baseline_downloading_24.xml b/app/src/main/res/drawable/baseline_downloading_24.xml
new file mode 100644
index 0000000..95f1fc6
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_downloading_24.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/baseline_home_24.xml b/app/src/main/res/drawable/baseline_home_24.xml
new file mode 100644
index 0000000..ad8e698
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_home_24.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/baseline_keyboard_backspace_24.xml b/app/src/main/res/drawable/baseline_keyboard_backspace_24.xml
new file mode 100644
index 0000000..a23629f
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_keyboard_backspace_24.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/baseline_more_vert_24.xml b/app/src/main/res/drawable/baseline_more_vert_24.xml
new file mode 100644
index 0000000..c73e4c0
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_more_vert_24.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/baseline_settings_24.xml b/app/src/main/res/drawable/baseline_settings_24.xml
new file mode 100644
index 0000000..a779a56
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_settings_24.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/bg_settings.xml b/app/src/main/res/drawable/bg_settings.xml
new file mode 100644
index 0000000..eb620ab
--- /dev/null
+++ b/app/src/main/res/drawable/bg_settings.xml
@@ -0,0 +1,16 @@
+
+
+ -
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/bnv_tab_item_foreground.xml b/app/src/main/res/drawable/bnv_tab_item_foreground.xml
new file mode 100644
index 0000000..79de3e3
--- /dev/null
+++ b/app/src/main/res/drawable/bnv_tab_item_foreground.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/close_ripple_effect.xml b/app/src/main/res/drawable/close_ripple_effect.xml
new file mode 100644
index 0000000..6d43aac
--- /dev/null
+++ b/app/src/main/res/drawable/close_ripple_effect.xml
@@ -0,0 +1,16 @@
+
+
+ -
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/editext_bg.xml b/app/src/main/res/drawable/editext_bg.xml
new file mode 100644
index 0000000..b660a1e
--- /dev/null
+++ b/app/src/main/res/drawable/editext_bg.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/folder.xml b/app/src/main/res/drawable/folder.xml
new file mode 100644
index 0000000..c22df3f
--- /dev/null
+++ b/app/src/main/res/drawable/folder.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/lock.png b/app/src/main/res/drawable/lock.png
new file mode 100644
index 0000000..43d4033
Binary files /dev/null and b/app/src/main/res/drawable/lock.png differ
diff --git a/app/src/main/res/drawable/music.xml b/app/src/main/res/drawable/music.xml
new file mode 100644
index 0000000..4cb87fb
--- /dev/null
+++ b/app/src/main/res/drawable/music.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/not_ads.xml b/app/src/main/res/drawable/not_ads.xml
new file mode 100644
index 0000000..d257900
--- /dev/null
+++ b/app/src/main/res/drawable/not_ads.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/privacy_policy.xml b/app/src/main/res/drawable/privacy_policy.xml
new file mode 100644
index 0000000..d1b5820
--- /dev/null
+++ b/app/src/main/res/drawable/privacy_policy.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/profile.xml b/app/src/main/res/drawable/profile.xml
new file mode 100644
index 0000000..8593ee6
--- /dev/null
+++ b/app/src/main/res/drawable/profile.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/rate_me.xml b/app/src/main/res/drawable/rate_me.xml
new file mode 100644
index 0000000..c9565d0
--- /dev/null
+++ b/app/src/main/res/drawable/rate_me.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/share.xml b/app/src/main/res/drawable/share.xml
new file mode 100644
index 0000000..972437e
--- /dev/null
+++ b/app/src/main/res/drawable/share.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/storage.xml b/app/src/main/res/drawable/storage.xml
new file mode 100644
index 0000000..7cedfa7
--- /dev/null
+++ b/app/src/main/res/drawable/storage.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/tv_download.xml b/app/src/main/res/drawable/tv_download.xml
new file mode 100644
index 0000000..3378c05
--- /dev/null
+++ b/app/src/main/res/drawable/tv_download.xml
@@ -0,0 +1,16 @@
+
+
+ -
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/tv_paste.xml b/app/src/main/res/drawable/tv_paste.xml
new file mode 100644
index 0000000..4a798a0
--- /dev/null
+++ b/app/src/main/res/drawable/tv_paste.xml
@@ -0,0 +1,16 @@
+
+
+ -
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/version.xml b/app/src/main/res/drawable/version.xml
new file mode 100644
index 0000000..6ee3199
--- /dev/null
+++ b/app/src/main/res/drawable/version.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/app/src/main/res/font/poppins.ttf b/app/src/main/res/font/poppins.ttf
new file mode 100644
index 0000000..246a861
Binary files /dev/null and b/app/src/main/res/font/poppins.ttf differ
diff --git a/app/src/main/res/font/poppins_bold.ttf b/app/src/main/res/font/poppins_bold.ttf
new file mode 100644
index 0000000..44313ca
Binary files /dev/null and b/app/src/main/res/font/poppins_bold.ttf differ
diff --git a/app/src/main/res/font/poppins_bold_italic.ttf b/app/src/main/res/font/poppins_bold_italic.ttf
new file mode 100644
index 0000000..939fc7d
Binary files /dev/null and b/app/src/main/res/font/poppins_bold_italic.ttf differ
diff --git a/app/src/main/res/font/poppins_medium.ttf b/app/src/main/res/font/poppins_medium.ttf
new file mode 100644
index 0000000..5b46f19
Binary files /dev/null and b/app/src/main/res/font/poppins_medium.ttf differ
diff --git a/app/src/main/res/font/poppins_semibold.ttf b/app/src/main/res/font/poppins_semibold.ttf
new file mode 100644
index 0000000..3bbad2a
Binary files /dev/null and b/app/src/main/res/font/poppins_semibold.ttf differ
diff --git a/app/src/main/res/font/poppins_semibold_italic.ttf b/app/src/main/res/font/poppins_semibold_italic.ttf
new file mode 100644
index 0000000..74a7c43
Binary files /dev/null and b/app/src/main/res/font/poppins_semibold_italic.ttf differ
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..622c79b
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fetching_dialog.xml b/app/src/main/res/layout/fetching_dialog.xml
new file mode 100644
index 0000000..d41e210
--- /dev/null
+++ b/app/src/main/res/layout/fetching_dialog.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_app_settings.xml b/app/src/main/res/layout/fragment_app_settings.xml
new file mode 100644
index 0000000..06dc0af
--- /dev/null
+++ b/app/src/main/res/layout/fragment_app_settings.xml
@@ -0,0 +1,233 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_download.xml b/app/src/main/res/layout/fragment_download.xml
new file mode 100644
index 0000000..e3ee0c2
--- /dev/null
+++ b/app/src/main/res/layout/fragment_download.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
new file mode 100644
index 0000000..a53a205
--- /dev/null
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -0,0 +1,226 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_media_items.xml b/app/src/main/res/layout/fragment_media_items.xml
new file mode 100644
index 0000000..8c91397
--- /dev/null
+++ b/app/src/main/res/layout/fragment_media_items.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_privacy_policy.xml b/app/src/main/res/layout/fragment_privacy_policy.xml
new file mode 100644
index 0000000..af46b9f
--- /dev/null
+++ b/app/src/main/res/layout/fragment_privacy_policy.xml
@@ -0,0 +1,185 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_folders.xml b/app/src/main/res/layout/list_folders.xml
new file mode 100644
index 0000000..fb02a78
--- /dev/null
+++ b/app/src/main/res/layout/list_folders.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/video_items.xml b/app/src/main/res/layout/video_items.xml
new file mode 100644
index 0000000..58e4526
--- /dev/null
+++ b/app/src/main/res/layout/video_items.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/bottom_navigation_menu.xml b/app/src/main/res/menu/bottom_navigation_menu.xml
new file mode 100644
index 0000000..ed06f62
--- /dev/null
+++ b/app/src/main/res/menu/bottom_navigation_menu.xml
@@ -0,0 +1,22 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/more_menu.xml b/app/src/main/res/menu/more_menu.xml
new file mode 100644
index 0000000..c10ce07
--- /dev/null
+++ b/app/src/main/res/menu/more_menu.xml
@@ -0,0 +1,15 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..c209e78
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..b2dfe3d
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..4f0f1d6
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..62b611d
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..948a307
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1b9a695
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..28d4b77
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9287f50
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..aa7d642
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9126ae3
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/navigation/navigation.xml b/app/src/main/res/navigation/navigation.xml
new file mode 100644
index 0000000..63d508f
--- /dev/null
+++ b/app/src/main/res/navigation/navigation.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/raw/fetching.json b/app/src/main/res/raw/fetching.json
new file mode 100644
index 0000000..01ff39d
--- /dev/null
+++ b/app/src/main/res/raw/fetching.json
@@ -0,0 +1 @@
+{"nm":"sand timer","ddd":0,"h":120,"w":120,"meta":{"g":"LottieFiles AE 0.1.21"},"layers":[{"ty":3,"nm":"Null 3","sr":1,"st":0,"op":240,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[50,50,0],"ix":1},"s":{"a":0,"k":[73,73,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[60,60,0],"ix":2},"r":{"a":1,"k":[{"o":{"x":0.742,"y":0},"i":{"x":0.667,"y":1},"s":[0],"t":16},{"s":[-180],"t":43}],"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":0,"ix":11}},"ef":[],"ind":1},{"ty":4,"nm":"top sand","sr":1,"st":0,"op":60,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":true,"ao":0,"ks":{"a":{"a":0,"k":[-388.008,75.466,0],"ix":1},"s":{"a":0,"k":[136.986,136.986,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[50,35.334,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"masksProperties":[{"nm":"top mask","inv":false,"mode":"a","x":{"a":0,"k":0,"ix":4},"o":{"a":0,"k":100,"ix":3},"pt":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.833,"y":0.833},"s":[{"c":true,"i":[[0,0],[8.5,-3],[0,0],[0,0],[0,0]],"o":[[0,0],[-8.896,3.14],[0,0],[0,0],[0,0]],"v":[[-371.449,64.5],[-389.008,58.5],[-404,64.5],[-404,87.25],[-371.449,87.25]]}],"t":-4},{"o":{"x":0.167,"y":0.167},"i":{"x":0.557,"y":1},"s":[{"c":true,"i":[[0,0],[3.516,5.35],[0,0],[0,0],[0,0]],"o":[[0,0],[-4.234,-6.15],[0,0],[0,0],[0,0]],"v":[[-379.199,83.761],[-392.024,74.823],[-404,75.511],[-404,87.601],[-371.449,87.601]]}],"t":19},{"s":[{"c":true,"i":[[0,0],[9.25,0],[0,0],[0,0],[0,0]],"o":[[0,0],[-8.974,0],[0,0],[0,0],[0,0]],"v":[[-371.449,88],[-388.508,88],[-404,88],[-404,88],[-371.449,88]]}],"t":39.2138671875}],"ix":1}}],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Shape 2","ix":1,"cix":2,"np":2,"it":[{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.2588,0.7216,0.5843],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Shape 1","ix":2,"cix":2,"np":2,"it":[{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.2588,0.7216,0.5843],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":3,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[3.507,3.571],[0,0],[0,0],[0,2.437],[0,0],[-0.43,0],[0,0],[0,-0.43],[0,0],[1.489,-1.691],[0,0]],"o":[[0,0],[0,0],[-1.707,-1.739],[0,0],[0,-0.43],[0,0],[0.43,0],[0,0],[0,2.251],[0,0],[0,0]],"v":[[-390.332,80.46],[-392.903,77.973],[-397.727,73.057],[-400.374,66.58],[-400.374,65.02],[-399.595,64.241],[-376.422,64.241],[-375.643,65.02],[-375.643,67.039],[-377.952,73.151],[-382.162,77.929]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.2588,0.7216,0.5843],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":2,"parent":1},{"ty":4,"nm":"bottom sand 2","sr":1,"st":0,"op":60,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":true,"ao":0,"ks":{"a":{"a":0,"k":[-388.008,75.466,0],"ix":1},"s":{"a":0,"k":[136.986,-136.986,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[50,64.443,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"masksProperties":[{"nm":"top mask","inv":false,"mode":"a","x":{"a":0,"k":0,"ix":4},"o":{"a":0,"k":100,"ix":3},"pt":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[{"c":true,"i":[[0,0],[-8.5,0.021],[0,0],[0,0],[0,0]],"o":[[0,0],[8.896,-0.022],[0,0],[0,0],[0,0]],"v":[[-404,62.26],[-386.382,62.199],[-371.449,62.26],[-371.39,62],[-403.941,62]]}],"t":0},{"s":[{"c":true,"i":[[0,0],[-8.5,3],[0,0],[0,0],[0,0]],"o":[[0,0],[8.896,-3.14],[0,0],[0,0],[0,0]],"v":[[-404,95.75],[-386.382,87],[-371.449,95.75],[-371.39,58.25],[-403.941,58.25]]}],"t":39}],"ix":1}}],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Shape 2","ix":1,"cix":2,"np":2,"it":[{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.2588,0.7216,0.5843],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Shape 1","ix":2,"cix":2,"np":2,"it":[{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.2588,0.7216,0.5843],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":3,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,2.437],[0,0],[-0.43,0],[0,0],[0,-0.43],[0,0],[1.489,-1.691],[0,0],[0,0]],"o":[[0,0],[-1.707,-1.739],[0,0],[0,-0.43],[0,0],[0.43,0],[0,0],[0,2.251],[0,0],[0,0],[-3.071,3.486]],"v":[[-392.102,78.79],[-397.727,73.057],[-400.374,66.58],[-400.374,65.02],[-399.595,64.241],[-376.422,64.241],[-375.643,65.02],[-375.643,67.039],[-377.952,73.151],[-383.095,78.988],[-384.631,80.511]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.2588,0.7216,0.5843],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":3,"parent":1},{"ty":4,"nm":"filler path","sr":1,"st":0,"op":115,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[136.986,136.986,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[50.685,50,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Shape 1","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":false,"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,-18.312],[0.041,19]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":2,"lj":2,"ml":1,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"d":[{"nm":"dash","n":"d","v":{"a":0,"k":0,"ix":1}},{"nm":"offset","n":"o","v":{"a":0,"k":0,"ix":7}}],"c":{"a":0,"k":[0.2588,0.7216,0.5843],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":1,"k":[{"o":{"x":0.613,"y":-0.021},"i":{"x":0.363,"y":1},"s":[28],"t":-4},{"s":[100],"t":15.642578125}],"ix":2},"o":{"a":0,"k":0,"ix":3},"s":{"a":1,"k":[{"o":{"x":0.37,"y":0},"i":{"x":0.569,"y":1},"s":[0],"t":1},{"s":[100],"t":46}],"ix":1},"m":1}],"ind":4,"parent":1},{"ty":4,"nm":"botter","sr":1,"st":0,"op":240,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[-388.008,86.539,0],"ix":1},"s":{"a":0,"k":[136.986,136.986,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[50,50,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,3.284],[0,0],[0,0],[0,0],[-2.475,-2.522],[0,0],[1.626,-1.657],[0,0],[0,-3.534],[0,0],[0,0],[0,0],[2.171,2.464],[0,0],[-1.419,1.61],[0,0]],"o":[[0,0],[0,0],[0,0],[0,3.534],[0,0],[1.626,1.657],[0,0],[-2.475,2.522],[0,0],[0,0],[0,0],[0,-3.284],[0,0],[-1.419,-1.61],[0,0],[2.171,-2.464]],"v":[[-371.674,68.761],[-371.674,59.435],[-404.342,59.435],[-404.342,68.343],[-400.481,77.792],[-394.803,83.578],[-394.803,89.547],[-400.481,95.333],[-404.342,104.782],[-404.342,113.642],[-371.674,113.642],[-371.674,104.364],[-375.043,95.445],[-380.388,89.379],[-380.388,83.745],[-375.043,77.68]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":10,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"c":{"a":0,"k":[0.2588,0.7216,0.5843],"ix":3}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.9255,0.9725,0.9569],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":5,"parent":1},{"ty":4,"nm":"top fill","sr":1,"st":0,"op":240,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[-388.008,58.473,0],"ix":1},"s":{"a":0,"k":[136.986,136.986,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[49.985,7.498,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0.981,0],[0,0],[0,0.981],[0,0],[-0.981,0],[0,0],[0,-0.981],[0,0]],"o":[[0,0],[-0.981,0],[0,0],[0,-0.981],[0,0],[0.981,0],[0,0],[0,0.981]],"v":[[-369.606,60.249],[-406.411,60.249],[-408.187,58.473],[-408.187,58.473],[-406.411,56.698],[-369.606,56.698],[-367.83,58.473],[-367.83,58.473]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.9255,0.9725,0.9569],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":6,"parent":1},{"ty":4,"nm":"bottom fill","sr":1,"st":0,"op":240,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[-388.008,114.495,0],"ix":1},"s":{"a":0,"k":[136.986,136.986,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[50.015,92.116,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0.981,0],[0,0],[0,0.981],[0,0],[-0.981,0],[0,0],[0,-0.981],[0,0]],"o":[[0,0],[-0.981,0],[0,0],[0,-0.981],[0,0],[0.981,0],[0,0],[0,0.981]],"v":[[-369.606,116.27],[-406.411,116.27],[-408.187,114.495],[-408.187,114.495],[-406.411,112.719],[-369.606,112.719],[-367.83,114.495],[-367.83,114.495]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.9255,0.9725,0.9569],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":7,"parent":1},{"ty":4,"nm":"cristal","sr":1,"st":0,"op":240,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[-388.008,87.579,0],"ix":1},"s":{"a":0,"k":[136.986,136.986,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[50,50,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":1,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0.43],[0,0],[-1.706,1.741],[0,0],[3.507,3.571],[0,0],[0,2.437],[0,0],[-0.43,0],[0,0],[0,-0.43],[0,0],[1.489,-1.691],[0,0],[-3.071,-3.486],[0,0],[0,-2.252],[0,0],[0.43,0]],"o":[[-0.43,0],[0,0],[0,-2.437],[0,0],[3.506,-3.569],[0,0],[-1.707,-1.739],[0,0],[0,-0.43],[0,0],[0.43,0],[0,0],[0,2.251],[0,0],[-3.071,3.486],[0,0],[1.489,1.691],[0,0],[0,0.43],[0,0]],"v":[[-399.595,110.917],[-400.374,110.138],[-400.374,106.544],[-397.728,100.067],[-390.83,93.037],[-390.832,80.085],[-397.727,73.057],[-400.374,66.58],[-400.374,65.02],[-399.595,64.241],[-376.422,64.241],[-375.643,65.02],[-375.643,67.039],[-377.952,73.151],[-384.381,80.448],[-384.381,92.676],[-377.952,99.973],[-375.643,106.087],[-375.643,110.138],[-376.422,110.917]]},"ix":2}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":8,"parent":1}],"v":"5.5.7","fr":24,"op":48,"ip":0,"assets":[]}
\ No newline at end of file
diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml
new file mode 100644
index 0000000..8f5baa3
--- /dev/null
+++ b/app/src/main/res/values-night/colors.xml
@@ -0,0 +1,17 @@
+
+
+ #FF000000
+ #FFFFFFFF
+ #333333
+
+ #000
+ #A6A5A5
+
+ #36454F
+
+ #fff
+
+ #36454F
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml
new file mode 100644
index 0000000..2666460
--- /dev/null
+++ b/app/src/main/res/values-night/themes.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..fe8eca5
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,16 @@
+
+
+ #FF000000
+ #FFFFFFFF
+ #fff
+
+ #fff
+ #A6A5A5
+
+ #36454F
+
+ #000
+
+ #fff
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..eb9b819
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,76 @@
+
+ TK Video Downloader
+
+ Hello blank fragment
+ Tiktok Video Downloader
+ Enter Tiktok Url
+ Download
+
+ Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.4) Gecko/20100101 Firefox/117.0
+ .tiktok.com
+ Media Permission
+ Please allow media permission to continue…
+ video_url
+ video items
+ 25 MB
+ 0:00
+ TK Downloder
+ Paste Tiktok link here…
+ Home
+ app_settings
+ no_ads
+ Paste
+ clear_text
+ video.mp4
+ Fetching link please wait, it takes\nsome seconds…
+ Download without WaterMark
+ Download without WaterMark (HD)
+ Download Original Video
+ Download Audio (MP3)
+ img_profile
+ folder
+ Videos
+ (1)
+ 11 MB - 0.34
+ TextView
+ Share
+ View
+
+ Banner is implemented below, you can check it out
+ Small Native Ad
+ This is your native ad, i hope you like it?
+ Close
+ Reward ads is not ready yet
+ The interstitial ad wasn\'t ready yet.
+ Ad showed fullscreen content.
+ Ad recorded an impression.
+ Ad was clicked.
+ Ad dismissed fullscreen content.
+ Ad failed to show fullscreen content.
+ Admob ads are not loaded yet!
+ Large native Ads
+
+ Settings
+ Rate
+ Rate us
+ Storage
+ Privacy Policy
+ App Version
+ This Privacy Policy describes how your personal information is collected, used, and shared when you use the TikTok Video Downloader App.
+ Information We Collect:
+ The TikTok Video Downloader App does not collect any personally identifiable information about you. However, the app may request permission to access your device\'s external storage to save downloaded video and audio files. This permission is necessary for the proper functioning of the app.
+ Downloaded Files
+ The app allows users to download TikTok videos and audio in three different qualities: original, HD without watermark, and normal without watermark. These downloaded files are stored in the external storage of your device, and the app requires external storage permission to save these files.
+ Usage of Downloaded Files
+ The TikTok Video Downloader App provides a feature to view and share the downloaded video and audio files. The app does not access or store any personal information related to the content of the downloaded files.
+ Sharing Features
+ The app allows users to share downloaded video and audio files through various external applications installed on their device, such as messaging apps or social media platforms. The app does not have access to or control over the content shared through these external applications.
+ Security
+ The security of your personal information is important to us, but please be aware that no method of transmission over the internet or electronic storage is 100% secure. While we strive to use commercially acceptable means to protect your personal information, we cannot guarantee its absolute security.
+ Changes to This Privacy Policy
+ We may update our Privacy Policy from time to time. Thus, you are advised to review this page periodically for any changes. We will notify you of any changes by posting the new Privacy Policy on this page. These changes are effective immediately after they are posted on this page.
+ Contact Us
+ If you have any questions or suggestions about our Privacy Policy, do not hesitate to contact us at askedumairbashir@gmail.com. By using the TikTok Video Downloader App, you agree to the collection and use of information in accordance with this policy.
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..41f561b
--- /dev/null
+++ b/app/src/main/res/values/themes.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml
new file mode 100644
index 0000000..fa0f996
--- /dev/null
+++ b/app/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000..9ee9997
--- /dev/null
+++ b/app/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/provider_paths.xml b/app/src/main/res/xml/provider_paths.xml
new file mode 100644
index 0000000..a075ef9
--- /dev/null
+++ b/app/src/main/res/xml/provider_paths.xml
@@ -0,0 +1,6 @@
+
+
+
+
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 0000000..901cacb
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,9 @@
+buildscript {
+ val agp_version by extra("8.1.4")
+ val agp_version1 by extra("8.1.4")
+}
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+plugins {
+ id("com.android.application") version "8.1.4" apply false
+ id("org.jetbrains.kotlin.android") version "1.9.0" apply false
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..3c5031e
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,23 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
+# Enables namespacing of each library's R class so that its R class includes only the
+# resources declared in the library itself and none from the library's dependencies,
+# thereby reducing the size of the R class for that library
+android.nonTransitiveRClass=true
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..e708b1c
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..953b299
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Fri Nov 17 12:35:10 PKT 2023
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000..4f906e0
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..107acd3
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/screenshots/Screenshot_20231130-145720_TK Video Downloader.jpg b/screenshots/Screenshot_20231130-145720_TK Video Downloader.jpg
new file mode 100644
index 0000000..b1cd129
Binary files /dev/null and b/screenshots/Screenshot_20231130-145720_TK Video Downloader.jpg differ
diff --git a/screenshots/Screenshot_20231130-145725_TK Video Downloader.jpg b/screenshots/Screenshot_20231130-145725_TK Video Downloader.jpg
new file mode 100644
index 0000000..20f1cf9
Binary files /dev/null and b/screenshots/Screenshot_20231130-145725_TK Video Downloader.jpg differ
diff --git a/screenshots/Screenshot_20231130-145727_TK Video Downloader.jpg b/screenshots/Screenshot_20231130-145727_TK Video Downloader.jpg
new file mode 100644
index 0000000..e6cd14f
Binary files /dev/null and b/screenshots/Screenshot_20231130-145727_TK Video Downloader.jpg differ
diff --git a/screenshots/Screenshot_20231130-145736_TK Video Downloader.jpg b/screenshots/Screenshot_20231130-145736_TK Video Downloader.jpg
new file mode 100644
index 0000000..b9939fa
Binary files /dev/null and b/screenshots/Screenshot_20231130-145736_TK Video Downloader.jpg differ
diff --git a/settings.gradle.kts b/settings.gradle.kts
new file mode 100644
index 0000000..5c6de72
--- /dev/null
+++ b/settings.gradle.kts
@@ -0,0 +1,18 @@
+pluginManagement {
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.name = "Tiktok Video Downloader (Without Watermark)"
+include(":app")
+
\ No newline at end of file