From e381baaeebc5b34b8c21f0f6d509b37e195af183 Mon Sep 17 00:00:00 2001
From: wangzhibo <wangzhibo@shsening.com>
Date: 星期五, 29 十一月 2024 11:10:46 +0800
Subject: [PATCH]  v2

---
 app/build.gradle.kts                                                              |    2 
 app/src/main/java/com/shsening/autouploadvideos/SessionProfileActivity.kt         |  232 +++++++
 app/src/main/java/com/shsening/autouploadvideos/HelpFragment.kt                   |   25 
 .idea/deploymentTargetSelector.xml                                                |   11 
 app/src/main/res/layout/upload_session.xml                                        |   41 +
 app/debug/app-debug.apk                                                           |    0 
 app/src/main/java/com/shsening/autouploadvideos/SessionProfileWebView.kt          |  118 +++
 app/src/main/res/layout/upload_list.xml                                           |   21 
 app/src/main/java/com/shsening/autouploadvideos/action/ActionDouyin.kt            |   57 +
 gradle/libs.versions.toml                                                         |    6 
 app/src/main/java/com/shsening/autouploadvideos/UploadSessionActivity.kt          |  266 ++++++++
 .idea/other.xml                                                                   |    2 
 app/src/main/res/layout/activity_session_profile.xml                              |  102 +++
 app/src/main/java/com/shsening/autouploadvideos/utils/DownloadHelper.kt           |   41 +
 app/src/main/java/com/shsening/autouploadvideos/utils/BroadcastReceiver.kt        |   28 
 app/src/main/java/com/shsening/autouploadvideos/action/ActionShipinhao.kt         |   34 
 app/src/main/java/com/shsening/autouploadvideos/SessionProfileListFragment.kt     |  130 +++
 app/src/main/res/layout/activity_main.xml                                         |    2 
 app/src/main/java/com/shsening/autouploadvideos/UploadFragment.kt                 |   24 
 app/src/main/res/layout/fragment_help.xml                                         |   46 +
 app/src/main/java/com/shsening/autouploadvideos/utils/Utils.kt                    |  125 +++
 app/src/main/res/layout/fragment_session_profile_list.xml                         |   28 
 app/src/main/java/com/shsening/autouploadvideos/AppConfig.kt                      |   17 
 app/src/main/java/com/shsening/autouploadvideos/UploadListFragment.kt             |  144 ++++
 app/src/main/res/values/strings.xml                                               |    4 
 app/src/main/res/layout/list_item_with_delete.xml                                 |   40 +
 app/src/main/AndroidManifest.xml                                                  |    7 
 app/src/main/java/com/shsening/autouploadvideos/action/PlatformActionInterface.kt |    7 
 app/src/main/java/com/shsening/autouploadvideos/MainActivity.kt                   |   37 
 app/src/main/java/com/shsening/autouploadvideos/SessionProfileManager.kt          |  199 ++++++
 app/src/main/java/com/shsening/autouploadvideos/action/ActionKuaishou.kt          |   41 
 /dev/null                                                                         |   28 
 app/src/main/java/com/shsening/autouploadvideos/CookieHelper.kt                   |   62 +
 app/src/main/res/layout/list_item_with_checkbox.xml                               |   48 +
 app/src/main/java/com/shsening/autouploadvideos/WebviewUtils.kt                   |    2 
 35 files changed, 1,836 insertions(+), 141 deletions(-)

diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml
index b268ef3..fd67af8 100644
--- a/.idea/deploymentTargetSelector.xml
+++ b/.idea/deploymentTargetSelector.xml
@@ -4,6 +4,17 @@
     <selectionStates>
       <SelectionState runConfigName="app">
         <option name="selectionMode" value="DROPDOWN" />
+        <DropdownSelection timestamp="2024-11-27T11:37:15.668942400Z">
+          <Target type="DEFAULT_BOOT">
+            <handle>
+              <DeviceId pluginId="Default" identifier="serial=127.0.0.1:5555;connection=03e18c1a" />
+            </handle>
+          </Target>
+        </DropdownSelection>
+        <DialogSelection />
+      </SelectionState>
+      <SelectionState runConfigName="SessionProfileActivity">
+        <option name="selectionMode" value="DROPDOWN" />
       </SelectionState>
     </selectionStates>
   </component>
diff --git a/.idea/other.xml b/.idea/other.xml
index 49481ad..104e542 100644
--- a/.idea/other.xml
+++ b/.idea/other.xml
@@ -262,7 +262,7 @@
           <option name="codename" value="q6q" />
           <option name="id" value="q6q" />
           <option name="manufacturer" value="Samsung" />
-          <option name="name" value="SM-F956B" />
+          <option name="name" value="Galaxy Z Fold6" />
           <option name="screenDensity" value="420" />
           <option name="screenX" value="1856" />
           <option name="screenY" value="2160" />
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index efaeade..70f1566 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -60,6 +60,7 @@
     implementation(libs.androidx.ui.tooling.preview)
     implementation(libs.androidx.material3)
     implementation(libs.material)
+    implementation(libs.firebase.storage.ktx)
     testImplementation(libs.junit)
     androidTestImplementation(libs.androidx.junit)
     androidTestImplementation(libs.androidx.espresso.core)
@@ -70,6 +71,5 @@
     implementation(libs.okhttp)
     implementation(libs.appcompat)
     implementation(libs.constraintlayout)
-
 
 }
\ No newline at end of file
diff --git a/app/debug/AutoUploadVideos-20241029.apk b/app/debug/AutoUploadVideos-20241029.apk
deleted file mode 100644
index ab1341b..0000000
--- a/app/debug/AutoUploadVideos-20241029.apk
+++ /dev/null
Binary files differ
diff --git a/app/debug/app-debug.apk b/app/debug/app-debug.apk
new file mode 100644
index 0000000..c7411eb
--- /dev/null
+++ b/app/debug/app-debug.apk
Binary files differ
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e6e0eb0..317079f 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -42,6 +42,13 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+
+        <activity android:name=".SessionProfileActivity"
+            android:windowSoftInputMode="adjustResize" />
+
+        <activity android:name=".UploadSessionActivity"
+            android:windowSoftInputMode="adjustResize" />
+
     </application>
 
 </manifest>
\ No newline at end of file
diff --git a/app/src/main/java/com/shsening/autouploadvideos/AppConfig.kt b/app/src/main/java/com/shsening/autouploadvideos/AppConfig.kt
index 5be029d..c69cdb4 100644
--- a/app/src/main/java/com/shsening/autouploadvideos/AppConfig.kt
+++ b/app/src/main/java/com/shsening/autouploadvideos/AppConfig.kt
@@ -1,6 +1,11 @@
 package com.shsening.autouploadvideos
 
-
+data class PlatformItem(
+    val id: Int,
+    val name: String,
+    val enabled: Boolean,
+    var url: String
+)
 class AppConfig {
     companion object {
         const val APP_VERSION_NAME = "1.1.0"
@@ -44,5 +49,15 @@
         const val URL_UPLOAD_SERVER_YOUTUBE = "https://creator.douyin.com/creator-micro/content/publish?enter_from=publish_page"
         const val URL_UPLOAD_SERVER_TIKTOK = "https://creator.douyin.com/creator-micro/content/publish?enter_from=publish_page"
 
+        val SESSION_PROFILE_PALTFORM_LISTS = listOf(
+            PlatformItem(1,"鎶栭煶",true,"https://creator.douyin.com/creator-micro/content/publish?enter_from=publish_page"),
+            PlatformItem(2,"蹇墜",true,"https://cp.kuaishou.com/article/publish/video"),
+            PlatformItem(3,"瑙嗛鍙�",true,"https://channels.weixin.qq.com/platform/post/create"),
+            PlatformItem(4,"灏忕孩涔�",false,"https://creator.douyin.com/creator-micro/content/publish?enter_from=publish_page"),
+            PlatformItem(5,"YouTube", false,"https://creator.douyin.com/creator-micro/content/publish?enter_from=publish_page"),
+            PlatformItem(6,"TikTok", false,"https://creator.douyin.com/creator-micro/content/publish?enter_from=publish_page")
+        )
+        val SESSION_PROFILE_TYPE: Map<Int, String> = mapOf(0 to "缇庡コ璺宠垶", 1 to "缇庡コ绌挎惌",2 to "AI缇庢櫙", 3 to "鎼炵瑧鍔ㄧ墿")
+
     }
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/shsening/autouploadvideos/CookieHelper.kt b/app/src/main/java/com/shsening/autouploadvideos/CookieHelper.kt
new file mode 100644
index 0000000..51cf155
--- /dev/null
+++ b/app/src/main/java/com/shsening/autouploadvideos/CookieHelper.kt
@@ -0,0 +1,62 @@
+import android.content.Context
+import android.webkit.CookieManager
+import com.shsening.autouploadvideos.AppConfig
+import org.json.JSONObject
+
+object CookieHelper {
+    private const val PREF_NAME = "CookieHelper"
+
+    fun saveSessionProfileUrlCookies(context: Context, sessionProfileId: String, url: String, cookies: String) {
+        val sharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
+        val sessionCookiesMap = sharedPreferences.getString(sessionProfileId, "{}")
+        val sessionCookies = JSONObject(sessionCookiesMap!!)
+        sessionCookies.put(url, cookies)
+        sharedPreferences.edit().putString(sessionProfileId, sessionCookies.toString()).apply()
+    }
+
+    fun getAllSessionProfileCookies(context: Context, sessionProfileId: String): Map<String, String> {
+        val sharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
+        val sessionCookiesMap = sharedPreferences.getString(sessionProfileId, "{}")
+        val sessionCookies = JSONObject(sessionCookiesMap!!)
+        return sessionCookies.keys().asSequence().associateWith { sessionCookies.getString(it) }
+    }
+
+    fun removeCookiesForUrl(url: String) {
+        val cookieManager = CookieManager.getInstance()
+        val cookies = cookieManager.getCookie(url) // 鑾峰彇鐗瑰畾 URL 鐨勬墍鏈� Cookie
+        if (cookies != null) {
+            val cookieArray = cookies.split(";") // 鎸夊垎鍙峰垎闅斿涓� Cookie
+            for (cookie in cookieArray) {
+                val cookieParts = cookie.split("=")
+                if (cookieParts.size > 0) {
+                    val cookieName = cookieParts[0].trim()
+                    // 璁剧疆涓�涓繃鏈熺殑 Cookie 瑕嗙洊鍘熸潵鐨�
+                    cookieManager.setCookie(url, "$cookieName=; Expires=Thu, 01 Jan 1970 00:00:00 GMT")
+                }
+            }
+            // 纭繚灏嗘洿鏀瑰悓姝ュ埌瀛樺偍涓�
+            cookieManager.flush()
+        }
+    }
+
+    fun removeCookieForAllPlatform(){
+        AppConfig.SESSION_PROFILE_PALTFORM_LISTS.forEach { item ->
+            removeCookiesForUrl(item.url)
+        }
+    }
+
+    fun saveSessionCookies(context: Context,sessionProfileId:String) {
+        var cookieManager = CookieManager.getInstance()
+        AppConfig.SESSION_PROFILE_PALTFORM_LISTS.forEach { item ->
+            val cookies = cookieManager.getCookie(item.url)
+            if (cookies != null) {
+                saveSessionProfileUrlCookies(
+                    context,
+                    sessionProfileId,
+                    item.url,
+                    cookies
+                )
+            }
+        }
+    }
+}
diff --git a/app/src/main/java/com/shsening/autouploadvideos/HelpFragment.kt b/app/src/main/java/com/shsening/autouploadvideos/HelpFragment.kt
index a1a692b..5b84ed9 100644
--- a/app/src/main/java/com/shsening/autouploadvideos/HelpFragment.kt
+++ b/app/src/main/java/com/shsening/autouploadvideos/HelpFragment.kt
@@ -1,12 +1,17 @@
 package com.shsening.autouploadvideos
 
+import android.content.ClipData
+import android.content.ClipboardManager
+import android.content.Context
 import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import android.webkit.WebView
+import android.widget.ImageView
+import android.widget.TextView
+import android.widget.Toast
 import androidx.fragment.app.Fragment
-
 
 class HelpFragment : Fragment() {
 
@@ -17,8 +22,26 @@
         savedInstanceState: Bundle?
     ): View? {
         val view = inflater.inflate(R.layout.fragment_help, container, false)
+
+        val textView = view.findViewById<TextView>(R.id.androidIdText);
+        textView.text = "Android ID: ${AppConfig.CLIENT_ANDROID_ID }"
+        textView.setOnClickListener {
+            val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
+            val clip = ClipData.newPlainText("label", textView.text)
+            clipboard.setPrimaryClip(clip)
+            Toast.makeText(requireContext(), AppConfig.MSG_MY_TAB_COPY_TO_CLIPBOARD, Toast.LENGTH_SHORT).show()
+        }
+
+        // 鍔犺浇鍥剧墖
+        val imageView = view.findViewById<ImageView>(R.id.imageView)
+        imageView.setImageResource(R.drawable.qrcode) // 璇锋浛鎹负浣犵殑鍥剧墖
+
+        // 璁剧疆绠�浠�
+        view.findViewById<TextView>(R.id.descriptionText).text = AppConfig.MSG_MY_TAB_ADD_WECHAT
+
         webView = view.findViewById(R.id.webView)
         webView.loadUrl("file:///android_asset/help/help.html")
+
         return view
     }
 }
diff --git a/app/src/main/java/com/shsening/autouploadvideos/MainActivity.kt b/app/src/main/java/com/shsening/autouploadvideos/MainActivity.kt
index ffa630e..2bc80da 100644
--- a/app/src/main/java/com/shsening/autouploadvideos/MainActivity.kt
+++ b/app/src/main/java/com/shsening/autouploadvideos/MainActivity.kt
@@ -2,41 +2,22 @@
 
 import android.Manifest
 import android.app.AlertDialog
-import android.content.ActivityNotFoundException
 import android.content.Context
-import android.content.Intent
 import android.content.pm.PackageManager
 import android.os.Bundle
 import android.view.View
 import android.widget.Button
 import androidx.appcompat.app.AppCompatActivity
 import android.graphics.Color
-import android.net.Uri
 import android.provider.Settings
-import android.util.Log
 import android.webkit.WebView
-import android.widget.TextView
-import android.widget.Toast
-import androidx.core.content.FileProvider
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.FragmentManager
+import com.shsening.autouploadvideos.utils.Utils
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
-import okhttp3.Call
-import okhttp3.Callback
-import okhttp3.OkHttpClient
-import okhttp3.Request
-import okhttp3.Response
-import org.json.JSONArray
-import org.json.JSONObject
-import java.io.File
-import java.io.IOException
-import kotlinx.coroutines.*
-import okhttp3.internal.wait
-import java.io.FileOutputStream
-import java.util.concurrent.CountDownLatch
 
 
 class MainActivity : AppCompatActivity() {
@@ -66,20 +47,26 @@
         fragmentManager = supportFragmentManager
 
         // 榛樿鏄剧ず绗竴涓� Fragment
+        /*
         setCurrentFragment(UploadFragment())
-
         findViewById<Button>(R.id.tabUpload).setOnClickListener {
             setCurrentFragment(UploadFragment())
             highlightTab(it)
         }
+         */
+        setCurrentFragment(UploadListFragment())
+        findViewById<Button>(R.id.tabUpload).setOnClickListener {
+            setCurrentFragment(UploadListFragment())
+            highlightTab(it)
+        }
 
-        findViewById<Button>(R.id.tabHelp).setOnClickListener {
-            setCurrentFragment(HelpFragment())
+        findViewById<Button>(R.id.tabSetting).setOnClickListener {
+            setCurrentFragment(SessionProfileListFragment())
             highlightTab(it)
         }
 
         findViewById<Button>(R.id.tabMy).setOnClickListener {
-            setCurrentFragment(MyFragment())
+            setCurrentFragment(HelpFragment())
             highlightTab(it)
         }
         CoroutineScope(Dispatchers.IO).launch {
@@ -106,7 +93,7 @@
     private fun highlightTab(selectedButton: View) {
         val tabButtons = listOf(
             findViewById<Button>(R.id.tabUpload),
-            findViewById<Button>(R.id.tabHelp),
+            findViewById<Button>(R.id.tabSetting),
             findViewById<Button>(R.id.tabMy)
         )
 
diff --git a/app/src/main/java/com/shsening/autouploadvideos/MyFragment.kt b/app/src/main/java/com/shsening/autouploadvideos/MyFragment.kt
deleted file mode 100644
index 26d6a45..0000000
--- a/app/src/main/java/com/shsening/autouploadvideos/MyFragment.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.shsening.autouploadvideos
-
-import android.content.ClipData
-import android.content.ClipboardManager
-import android.content.Context
-import android.os.Bundle
-import android.provider.Settings
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.ImageView
-import android.widget.TextView
-import android.widget.Toast
-import androidx.fragment.app.Fragment
-
-class MyFragment : Fragment() {
-
-    override fun onCreateView(
-        inflater: LayoutInflater, container: ViewGroup?,
-        savedInstanceState: Bundle?
-    ): View? {
-        val view = inflater.inflate(R.layout.fragment_my, container, false)
-
-
-        val textView = view.findViewById<TextView>(R.id.androidIdText);
-        textView.text = "Android ID: ${AppConfig.CLIENT_ANDROID_ID }"
-        textView.setOnClickListener {
-            val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
-            val clip = ClipData.newPlainText("label", textView.text)
-            clipboard.setPrimaryClip(clip)
-
-            Toast.makeText(requireContext(), AppConfig.MSG_MY_TAB_COPY_TO_CLIPBOARD, Toast.LENGTH_SHORT).show()
-        }
-
-
-        // 鍔犺浇鍥剧墖
-        val imageView = view.findViewById<ImageView>(R.id.imageView)
-        imageView.setImageResource(R.drawable.qrcode) // 璇锋浛鎹负浣犵殑鍥剧墖
-
-        // 璁剧疆绠�浠�
-        view.findViewById<TextView>(R.id.descriptionText).text = AppConfig.MSG_MY_TAB_ADD_WECHAT
-
-        return view
-    }
-}
diff --git a/app/src/main/java/com/shsening/autouploadvideos/SessionProfileActivity.kt b/app/src/main/java/com/shsening/autouploadvideos/SessionProfileActivity.kt
new file mode 100644
index 0000000..c8564da
--- /dev/null
+++ b/app/src/main/java/com/shsening/autouploadvideos/SessionProfileActivity.kt
@@ -0,0 +1,232 @@
+package com.shsening.autouploadvideos
+
+import CookieHelper
+import CookieHelper.saveSessionProfileUrlCookies
+import Profile
+import SessionProfile
+import SessionProfileManager
+import android.app.Activity
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import android.view.View
+import android.webkit.CookieManager
+import android.webkit.WebChromeClient
+import android.webkit.WebView
+import android.webkit.WebViewClient
+import android.widget.ArrayAdapter
+import android.widget.EditText
+import android.widget.LinearLayout
+import android.widget.ProgressBar
+import android.widget.Spinner
+import android.widget.Switch
+import android.widget.TextView
+import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
+import java.util.UUID
+
+
+class SessionProfileActivity : AppCompatActivity() {
+
+    private lateinit var sessionProfileManager: SessionProfileManager
+    private lateinit var sessionProfile: SessionProfile
+    private val appConfigItems = AppConfig.SESSION_PROFILE_PALTFORM_LISTS // 鑾峰彇骞冲彴淇℃伅鍒楄〃
+    private lateinit var editName: EditText
+    private lateinit var spinnerType: Spinner
+    private lateinit var switchContainer: LinearLayout
+    private lateinit var sessionProfileWebView:SessionProfileWebView
+
+    private var isNewSessionProfile:Boolean = false;
+
+    private lateinit var progressBar: ProgressBar
+
+    private lateinit var activityReference: SessionProfileActivity
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_session_profile)
+        activityReference = this
+
+        // 鑾峰彇浼犲叆鐨� SessionProfile
+        sessionProfile = intent.getSerializableExtra("sessionProfile") as? SessionProfile
+            ?: SessionProfile(
+                id = "",
+                name = "",
+                type = 0,
+                lastUploadTime = "",
+                profiles = mutableListOf()
+            )
+
+        if (sessionProfile.id == ""){
+            isNewSessionProfile = true
+            sessionProfile.id = UUID.randomUUID().toString().replace("-", "")
+            findViewById<TextView>(R.id.txt_session_id).text = "new:"+sessionProfile.id
+        }else {
+            findViewById<TextView>(R.id.txt_session_id).text = sessionProfile.id
+        }
+
+        editName = findViewById(R.id.edit_name)
+        findViewById<TextView>(R.id.edit_name).text = sessionProfile.name
+
+        spinnerType = findViewById(R.id.spinner_type)
+        spinnerType.adapter = ArrayAdapter(
+            this,
+            android.R.layout.simple_spinner_item,
+            AppConfig.SESSION_PROFILE_TYPE.values.toList()
+        )
+        spinnerType.setSelection(sessionProfile.type)
+
+        switchContainer = findViewById(R.id.switch_container)
+        setupSwitches()
+
+        // 鍒濆鍖� SessionProfileManager
+        sessionProfileManager = SessionProfileManager(this)
+
+        progressBar = findViewById(R.id.progressBar)
+        sessionProfileWebView = findViewById<SessionProfileWebView>(R.id.sessionProfileWebView)
+        sessionProfileWebView.setInitialScale(75) // 鍒濆缂╂斁姣斾緥
+        sessionProfileWebView.isFocusableInTouchMode = true
+        try{
+            Log.e("shsening", sessionProfile.id)
+
+            Log.e("shsening", CookieManager.getInstance().getCookie(AppConfig.URL_UPLOAD_SERVER_DOUYIN))
+
+        }catch(e:Exception){
+            Log.e("shsening", "there is no cookie founded")
+
+        }
+        sessionProfileWebView.loadSessionProfileCookies(sessionProfile.id)
+        try{
+            Log.e("shsening", CookieManager.getInstance().getCookie(AppConfig.URL_UPLOAD_SERVER_DOUYIN))
+
+        }catch(e:Exception){
+            Log.e("shsening", "there is no cookie founded")
+
+        }
+        sessionProfileWebView.webViewClient = object : WebViewClient() {
+
+            override fun onPageStarted(
+                view: WebView?,
+                url: String?,
+                favicon: android.graphics.Bitmap?
+            ) {
+                super.onPageStarted(view, url, favicon)
+                progressBar.visibility = View.VISIBLE
+            }
+            override fun onPageFinished(view: WebView?, url: String?) {
+                super.onPageFinished(view, url)
+                progressBar.visibility = View.GONE
+                url?.let{
+                    Log.e("shsening", url)
+                    try {
+                        val cookies = CookieManager.getInstance().getCookie(url)
+                        if (cookies != null) {
+                            CookieHelper.saveSessionProfileUrlCookies(
+                                activityReference,
+                                sessionProfile.id,
+                                url,
+                                cookies
+                            )
+                        } else {
+                            Log.w("shsening", "No cookies found for URL: $url")
+                        }
+                    } catch (e: java.lang.Exception) {
+                        Log.e("CookieHelper", "Failed to get cookies: ", e)
+                    }
+                }
+            }
+        }
+        sessionProfileWebView.webChromeClient = object : WebChromeClient() {
+            override fun onShowCustomView(view: View?, callback: CustomViewCallback?) {
+                super.onShowCustomView(view, callback)
+                view?.requestFocus()
+            }
+        }
+        // 淇濆瓨鎸夐挳鐨勭洃鍚�
+        findViewById<TextView>(R.id.btn_save).setOnClickListener {
+            saveSessionProfile()
+        }
+        findViewById<TextView>(R.id.btn_back).setOnClickListener {
+            finish()
+        }
+    }
+
+
+    private fun setupSwitches() {
+        switchContainer.removeAllViews()
+
+        // 鍒涘缓涓�涓按骞崇殑 LinearLayout
+        var horizontalLayout: LinearLayout? = null
+
+        // 閬嶅巻浠� AppConfig 鑾峰彇鐨勬墍鏈夊钩鍙伴」鐩�
+        for ((index, platform) in appConfigItems.withIndex()) {
+            if (index % 2 == 0) {
+                // 姣忎袱椤瑰垱寤轰竴涓柊鐨勬按骞冲竷灞�
+                horizontalLayout = LinearLayout(this).apply {
+                    orientation = LinearLayout.HORIZONTAL
+                    layoutParams = LinearLayout.LayoutParams(
+                        LinearLayout.LayoutParams.MATCH_PARENT,
+                        LinearLayout.LayoutParams.WRAP_CONTENT
+                    )
+                }
+            }
+
+            val switchView:Switch = Switch(this).apply {
+                text = platform.name
+                val existingProfile = sessionProfile.profiles.find { it.name == platform.name }
+                isChecked = existingProfile?.status ?: false
+                isEnabled = platform.enabled
+
+                // 寮�鍏崇洃鍚櫒
+                setOnCheckedChangeListener { _, isChecked ->
+                    if (existingProfile != null) {
+                        existingProfile.status = isChecked
+                    } else {
+                        sessionProfile.addOrUpdateProfile(Profile(name = platform.name, status = isChecked))
+                    }
+                    if (isChecked) {
+                        //sessionProfileWebView.loadSessionProfileCookies(sessionProfile.id)
+                        sessionProfileWebView.loadUrl(platform.url)
+                    }
+                }
+                layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f).apply {
+                    marginStart = 8
+                    marginEnd = 8
+                }
+            }
+
+            // 娣诲姞 Switch 鍒版按骞冲竷灞�
+            horizontalLayout?.addView(switchView)
+
+            // 濡傛灉鏄伓鏁扮储寮曟垨鑰呮渶鍚庝竴涓」鐩紝娣诲姞姘村钩甯冨眬鍒颁富瀹瑰櫒
+            if (index % 2 == 1 || index == appConfigItems.size - 1) {
+                switchContainer.addView(horizontalLayout)
+            }
+        }
+    }
+
+    private fun saveSessionProfile() {
+        try {
+            CookieHelper.saveSessionCookies(this,sessionProfile.id)
+            val name = editName.text.toString().trim() // 鑾峰彇杈撳叆鐨勫悕绉�
+            if (name.isEmpty()) {
+                Toast.makeText(this, "Name cannot be empty!", Toast.LENGTH_SHORT).show()
+                return
+            }
+            if (isNewSessionProfile and sessionProfileManager.checkProfileNameExist(name)){
+                Toast.makeText(this, "Name already exist !", Toast.LENGTH_SHORT).show()
+                return // 涓嶄繚瀛�
+            }
+            sessionProfile.name = name
+            sessionProfile.type = spinnerType.selectedItemPosition
+            sessionProfileManager.addOrUpdateSessionProfile(sessionProfile)
+            sessionProfileManager.saveToFile()
+
+            Toast.makeText(this, "Session profile saved", Toast.LENGTH_SHORT).show()
+            setResult(Activity.RESULT_OK, Intent())
+            finish()
+        }catch (e:Exception){
+            e.printStackTrace()
+        }
+    }
+}
diff --git a/app/src/main/java/com/shsening/autouploadvideos/SessionProfileListFragment.kt b/app/src/main/java/com/shsening/autouploadvideos/SessionProfileListFragment.kt
new file mode 100644
index 0000000..853b2e1
--- /dev/null
+++ b/app/src/main/java/com/shsening/autouploadvideos/SessionProfileListFragment.kt
@@ -0,0 +1,130 @@
+package com.shsening.autouploadvideos
+
+import SessionProfile
+import SessionProfileManager
+import android.app.Activity
+import android.app.AlertDialog
+import android.content.Intent
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.AdapterView
+import android.widget.ArrayAdapter
+import android.widget.Button
+import android.widget.ListView
+import androidx.fragment.app.Fragment
+import android.widget.TextView
+import com.shsening.autouploadvideos.utils.Utils
+import java.io.Serializable
+
+class SessionProfileListFragment : Fragment() {
+
+    private lateinit var listView: ListView
+    private lateinit var btnNew: View
+    private val REQUEST_CODE = 100
+
+    private val sessionProfiles = mutableListOf<SessionProfile>() // Replace with your real data source
+
+    override fun onCreateView(
+        inflater: LayoutInflater, container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View {
+        val view = inflater.inflate(R.layout.fragment_session_profile_list, container, false)
+
+        listView = view.findViewById(R.id.list_view)
+        btnNew = view.findViewById(R.id.btn_new)
+
+        setupListView()
+        setupNewButton()
+
+        return view
+    }
+
+    private fun setupListView() {
+        // 娓呯┖閫傞厤鍣�
+        listView.adapter = null
+
+        // 浠� SessionProfileManager 鑾峰彇鎵�鏈夌殑 SessionProfile
+        val sessionProfiles = SessionProfileManager(requireContext()).getAllProfiles()
+
+        // 鑷畾涔夐�傞厤鍣ㄥ疄鐜板垹闄ゆ寜閽姛鑳�
+        val adapter = object : ArrayAdapter<SessionProfile>(
+            requireContext(),
+            android.R.layout.simple_list_item_2,
+            sessionProfiles
+        ) {
+            override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
+                val inflater = LayoutInflater.from(context)
+                val view = convertView ?: inflater.inflate(R.layout.list_item_with_delete, parent, false)
+
+                // 鑾峰彇褰撳墠鐨� SessionProfile
+                val sessionProfile = getItem(position)
+
+                // 濉厖鏁版嵁
+                val text1 = view.findViewById<TextView>(android.R.id.text1)
+                val textType = Utils.getSessionProfileValueByPosition(sessionProfile?.type)
+                text1.text = "${sessionProfile?.name} (${textType})"
+
+                val text2 = view.findViewById<TextView>(android.R.id.text2)
+                text2.text = sessionProfile?.lastUploadTime
+
+                // 璁剧疆鍒犻櫎鎸夐挳
+                val deleteButton = view.findViewById<Button>(R.id.deleteButton)
+                deleteButton.setOnClickListener {
+                    // 寮瑰嚭纭瀵硅瘽妗�
+                    AlertDialog.Builder(context)
+                        .setTitle("鍒犻櫎纭")
+                        .setMessage("纭畾瑕佸垹闄� ${sessionProfile?.name} 鍚楋紵")
+                        .setPositiveButton("纭") { _, _ ->
+                            // 浠庣鐞嗗櫒涓垹闄�
+                            sessionProfile?.let {
+                                SessionProfileManager(requireContext()).removeProfile(it.id)
+                            }
+                            // 鍒锋柊鍒楄〃
+                            setupListView()
+                        }
+                        .setNegativeButton("鍙栨秷", null)
+                        .show()
+                }
+
+                // 璁剧疆琛岀偣鍑讳簨浠�
+                view.setOnClickListener {
+                    val intent = Intent(requireContext(), SessionProfileActivity::class.java)
+                    intent.putExtra("sessionProfile", sessionProfile as Serializable) // 浼犻�掗�変腑鐨� Profile 瀵硅薄
+                    startActivityForResult(intent, REQUEST_CODE)
+                }
+
+                return view
+            }
+        }
+
+        // 璁剧疆閫傞厤鍣ㄥ埌 ListView
+        listView.adapter = adapter
+
+        // 璁剧疆鐐瑰嚮浜嬩欢
+        listView.onItemClickListener =
+            AdapterView.OnItemClickListener { _, _, position, _ ->
+                val selectedProfile = sessionProfiles[position]
+                val intent = Intent(requireContext(), SessionProfileActivity::class.java)
+                intent.putExtra("sessionProfile", selectedProfile as Serializable) // 浼犻�掗�変腑鐨� Profile 瀵硅薄
+                startActivityForResult(intent, REQUEST_CODE)
+            }
+    }
+
+    // 鎺ユ敹鍒� Activity 杩斿洖缁撴灉鏃跺埛鏂� Fragment
+    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+        super.onActivityResult(requestCode, resultCode, data)
+        if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK) {
+            // 鍒锋柊 Fragment 鍐呭
+            setupListView()
+        }
+    }
+
+    private fun setupNewButton() {
+        btnNew.setOnClickListener {
+            val intent = Intent(requireContext(), SessionProfileActivity::class.java)
+            startActivityForResult(intent, REQUEST_CODE)
+        }
+    }
+}
diff --git a/app/src/main/java/com/shsening/autouploadvideos/SessionProfileManager.kt b/app/src/main/java/com/shsening/autouploadvideos/SessionProfileManager.kt
new file mode 100644
index 0000000..c2d2758
--- /dev/null
+++ b/app/src/main/java/com/shsening/autouploadvideos/SessionProfileManager.kt
@@ -0,0 +1,199 @@
+import android.content.Context
+import android.os.Parcel
+import com.shsening.autouploadvideos.AppConfig
+import org.json.JSONArray
+import org.json.JSONObject
+import java.io.File
+import java.io.Serializable
+import android.os.Parcelable
+import com.shsening.autouploadvideos.utils.Utils
+
+data class SessionProfile(
+    var id: String,
+    var name: String,
+    var type: Int,
+    var lastUploadTime: String,
+    val profiles: MutableList<Profile> = mutableListOf()
+) : Parcelable, Serializable { // 閫楀彿鍒嗛殧鎺ュ彛
+    // Parcelable 鐨勫疄鐜�
+    override fun writeToParcel(parcel: Parcel, flags: Int) {
+        parcel.writeString(id)
+        parcel.writeString(name)
+        parcel.writeInt(type)
+        parcel.writeString(lastUploadTime)
+        parcel.writeTypedList(profiles) // 瀵逛簬鍒楄〃锛屼娇鐢� writeTypedList
+    }
+    override fun describeContents(): Int {
+        return 0
+    }
+    // Parcelable 鐨� Companion Object
+    companion object CREATOR : Parcelable.Creator<SessionProfile> {
+        override fun createFromParcel(parcel: Parcel): SessionProfile {
+            val id = parcel.readString().orEmpty()
+            val name = parcel.readString().orEmpty()
+            val type = parcel.readInt()
+            val lastUploadTime = parcel.readString().orEmpty()
+            val profiles = mutableListOf<Profile>().apply {
+                parcel.readTypedList(this, Profile.CREATOR)
+            }
+            return SessionProfile(id, name, type, lastUploadTime, profiles)
+        }
+
+        override fun newArray(size: Int): Array<SessionProfile?> {
+            return arrayOfNulls(size)
+        }
+    }
+    // 娣诲姞鎴栨洿鏂� Profile 鐨勬柟娉�
+    fun addOrUpdateProfile(profile: Profile) {
+        val existingProfile = profiles.find { it.name == profile.name }
+        if (existingProfile != null) {
+            existingProfile.status = profile.status
+        } else {
+            profiles.add(profile)
+        }
+    }
+    fun getValidProfileNames(): List<String> {
+        return profiles.filter { it.status }.map { it.name }
+    }
+}
+
+data class Profile(
+    var name: String,
+    var status: Boolean
+) : Serializable,Parcelable {
+
+    override fun writeToParcel(parcel: Parcel, flags: Int) {
+        parcel.writeString(name)
+        parcel.writeByte(if (status) 1 else 0)
+    }
+    override fun describeContents(): Int {
+        return 0
+    }
+    companion object CREATOR : Parcelable.Creator<Profile> {
+        override fun createFromParcel(parcel: Parcel): Profile {
+            val name = parcel.readString().orEmpty()
+            val status = parcel.readByte() != 0.toByte()
+            return Profile(name, status)
+        }
+        override fun newArray(size: Int): Array<Profile?> {
+            return arrayOfNulls(size)
+        }
+    }
+}
+
+/**
+ * val profileManager = SessionProfileManager(context)
+ * profileManager.addProfile(1, "douyin", true)
+ * val profiles = profileManager.getProfile(1)
+ * profileManager.removeProfile(1)
+ * val allProfiles = profileManager.getAllProfiles()
+ */
+
+class SessionProfileManager(private val context: Context) {
+    companion object {
+        private const val FILE_NAME = "session_profiles.json"
+    }
+
+    private val sessionProfiles = mutableListOf<SessionProfile>()
+
+    init {
+        ensureFileExists() // 纭繚鏂囦欢瀛樺湪
+        loadProfiles()
+    }
+    // 纭繚鏂囦欢瀛樺湪
+    private fun ensureFileExists() {
+        val file = File(context.filesDir, FILE_NAME)
+        if (!file.exists()) {
+            file.writeText("[]") // 鍒涘缓绌� JSON 鏁扮粍浣滀负鍒濆鍐呭
+        }
+    }
+
+    // 鍔犺浇鏂囦欢鍐呭
+    private fun loadProfiles() {
+        val file = File(context.filesDir, FILE_NAME)
+        val jsonString = file.readText()
+        val jsonArray = JSONArray(jsonString)
+        sessionProfiles.clear()
+        for (i in 0 until jsonArray.length()) {
+            val jsonObj = jsonArray.getJSONObject(i)
+            sessionProfiles.add(jsonToSessionProfile(jsonObj))
+        }
+    }
+
+    // 淇濆瓨鍒版枃浠�
+    private fun saveProfiles() {
+        val jsonArray = JSONArray()
+        sessionProfiles.forEach { profile ->
+            jsonArray.put(sessionProfileToJson(profile))
+        }
+        val file = File(context.filesDir, FILE_NAME)
+        file.writeText(jsonArray.toString())
+    }
+
+    fun saveToFile() {
+        saveProfiles()
+    }
+
+    // Convert JSON to SessionProfile
+    private fun jsonToSessionProfile(json: JSONObject): SessionProfile {
+        val id = json.getString("id")
+        val name = json.getString("name")
+        val type = json.getInt("type")
+        val lastUploadTime = json.getString("lastUploadTime")
+        val profilesJsonArray = json.getJSONArray("profiles")
+        val profiles = mutableListOf<Profile>()
+        for (i in 0 until profilesJsonArray.length()) {
+            val profileJson = profilesJsonArray.getJSONObject(i)
+            profiles.add(Profile(profileJson.getString("name"), profileJson.getBoolean("status")))
+        }
+        return SessionProfile(id, name, type, lastUploadTime, profiles)
+    }
+
+    // Convert SessionProfile to JSON
+    private fun sessionProfileToJson(profile: SessionProfile): JSONObject {
+        val json = JSONObject()
+        json.put("id", profile.id)
+        json.put("name", profile.name)
+        json.put("type", profile.type)
+        json.put("lastUploadTime", profile.lastUploadTime)
+        val profilesJsonArray = JSONArray()
+        profile.profiles.forEach {
+            val profileJson = JSONObject()
+            profileJson.put("name", it.name)
+            profileJson.put("status", it.status)
+            profilesJsonArray.put(profileJson)
+        }
+        json.put("profiles", profilesJsonArray)
+        return json
+    }
+
+    // Get all session profiles
+    fun getAllProfiles(): List<SessionProfile> {
+        if (sessionProfiles.isEmpty()) {
+            loadProfiles()
+        }
+        return sessionProfiles.toList() // 灏嗗唴閮ㄧ殑 profiles 杩斿洖涓轰笉鍙彉鍒楄〃
+    }
+    // Add a new session profile
+    fun checkProfileNameExist(name: String): Boolean {
+        return sessionProfiles.any { it.name == name }
+    }
+
+    // Remove a session profile
+    fun removeProfile(id: String) {
+        sessionProfiles.removeAll { it.id == id }
+        saveProfiles()
+    }
+
+    // 3. 娣诲姞鎴栨洿鏂� SessionProfile
+    fun addOrUpdateSessionProfile(sessionProfile: SessionProfile) {
+        val existingProfile = sessionProfiles.find { it.id == sessionProfile.id }
+        if (existingProfile != null) {
+            val index = sessionProfiles.indexOf(existingProfile)
+            sessionProfiles[index] = sessionProfile
+        } else {
+            // 娣诲姞鏂扮殑 Profile
+            sessionProfiles.add(sessionProfile)
+        }
+    }
+}
diff --git a/app/src/main/java/com/shsening/autouploadvideos/SessionProfileWebView.kt b/app/src/main/java/com/shsening/autouploadvideos/SessionProfileWebView.kt
new file mode 100644
index 0000000..f8d1f67
--- /dev/null
+++ b/app/src/main/java/com/shsening/autouploadvideos/SessionProfileWebView.kt
@@ -0,0 +1,118 @@
+package com.shsening.autouploadvideos
+
+import CookieHelper
+import android.content.Context
+import android.os.Handler
+import android.os.Looper
+import android.text.TextUtils
+import android.util.AttributeSet
+import android.util.Log
+import android.webkit.CookieManager
+import android.webkit.CookieSyncManager
+import android.webkit.WebSettings
+import android.webkit.WebView
+import android.widget.Toast
+
+
+class SessionProfileWebView @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet? = null,
+    defStyle: Int = 0
+) : WebView(context, attrs, defStyle) {
+
+    init {
+        settings.javaScriptEnabled = true
+        settings.userAgentString = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
+        settings.javaScriptEnabled = true
+        settings.domStorageEnabled = true
+        settings.databaseEnabled = true
+        settings.setSupportZoom(true)
+        settings.builtInZoomControls = true
+        settings.displayZoomControls = false
+        settings.allowFileAccess = true
+        settings.textZoom = 50 // Set zoom level to 30%
+        settings.useWideViewPort = true
+        settings.loadWithOverviewMode = true
+        settings.layoutAlgorithm = WebSettings.LayoutAlgorithm.NORMAL
+        CookieManager.getInstance().setAcceptCookie(true) // 鎺ュ彈 Cookie
+        CookieManager.getInstance().setAcceptThirdPartyCookies(this, true) // 鎺ュ彈绗笁鏂� Cookie
+        settings.setCacheMode(WebSettings.LOAD_NO_CACHE)
+    }
+
+
+    // 鍔犺浇 SessionProfile 鐨勬墍鏈� URL-Cookie 鏄犲皠鍒� WebView
+    fun loadSessionProfileCookies(sessionProfileId: String) {
+        //CookieHelper.removeCookieForAllPlatform()
+        CookieManager.getInstance().removeAllCookies(null)
+        CookieManager.getInstance().flush()
+        val sessionCookies = CookieHelper.getAllSessionProfileCookies(context, sessionProfileId)
+        for ((url, cookies) in sessionCookies) {
+            splitCookieStringAndSetCookie(url,cookies)
+        }
+    }
+    private fun splitCookieStringAndSetCookie(url:String,cookies:String){
+        val cookie_part = cookies.split(";".toRegex()).dropLastWhile { it.isEmpty() }
+            .toTypedArray()
+        val cookieManager = CookieManager.getInstance()
+        if (cookie_part!=null) {
+            for (cook in cookie_part) {
+                //涓�瀹氳涓�涓竴涓猻et, 濡傛灉鏄嫾鎺ョ殑璇濓紝璁剧疆涓嶆垚鍔熴��
+                //cookieManager.setCookie(url, cook.trim{ it <= ' ' })
+                cookieManager.setCookie(url, cook.trim())
+            }
+        }
+        cookieManager.flush()
+    }
+
+    // 璁块棶鏌愪釜 URL 鏃讹紝淇濆瓨褰撳墠 SessionProfile 鐨� Cookie
+    fun saveCurrentSessionProfileUrlCookies(sessionProfileId:String, url: String) {
+        val cookieManager = CookieManager.getInstance()
+        val cookies = cookieManager.getCookie(url)
+        if (cookies != null) {
+            CookieHelper.saveSessionProfileUrlCookies(context, sessionProfileId, url, cookies)
+        }
+    }
+
+
+    override fun loadUrl(url: String) {
+        try{
+            val headers = mapOf(
+                "pragma" to "no-cache",
+                "priority" to "u=0, i",
+                "sec-ch-ua" to "\"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"",
+                "sec-ch-ua-mobile" to "?0",
+                "sec-ch-ua-platform" to "\"Windows\"",
+                "sec-fetch-dest" to "document",
+                "sec-fetch-mode" to "navigate",
+                "sec-fetch-site" to "none",
+                "sec-fetch-user" to "?1",
+                "upgrade-insecure-requests" to "1"
+                )
+            super.loadUrl(url,headers)
+        }catch (e:Exception){
+            e.printStackTrace()
+        }
+    }
+    fun loadUrlNoCache(url: String) {
+        try{
+            val headers = mapOf(
+                "pragma" to "no-cache",
+                "priority" to "u=0, i",
+                "sec-ch-ua" to "\"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"",
+                "sec-ch-ua-mobile" to "?0",
+                "sec-ch-ua-platform" to "\"Windows\"",
+                "sec-fetch-dest" to "document",
+                "sec-fetch-mode" to "navigate",
+                "sec-fetch-site" to "none",
+                "sec-fetch-user" to "?1",
+                "upgrade-insecure-requests" to "1"
+            )
+            super.clearCache(true)
+            super.loadUrl(url,headers)
+        }catch (e:Exception){
+            e.printStackTrace()
+        }
+    }
+
+}
+
diff --git a/app/src/main/java/com/shsening/autouploadvideos/UploadFragment.kt b/app/src/main/java/com/shsening/autouploadvideos/UploadFragment.kt
index a4a9525..2f30566 100644
--- a/app/src/main/java/com/shsening/autouploadvideos/UploadFragment.kt
+++ b/app/src/main/java/com/shsening/autouploadvideos/UploadFragment.kt
@@ -19,6 +19,10 @@
 import androidx.core.content.FileProvider
 import androidx.fragment.app.Fragment
 import androidx.lifecycle.lifecycleScope
+import com.shsening.autouploadvideos.action.ActionDouyin
+import com.shsening.autouploadvideos.action.ActionKuaishou
+import com.shsening.autouploadvideos.action.ActionShipinhao
+import com.shsening.autouploadvideos.utils.Utils
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
 import okhttp3.Call
@@ -49,7 +53,7 @@
 
     var uploadTaskList: MutableList<Utils.VideoUploadTaskInfo> =mutableListOf()
 
-    private lateinit var currentUploadVideoInfo:Utils.VideoUploadTaskInfo
+    private lateinit var currentUploadVideoInfo: Utils.VideoUploadTaskInfo
     private lateinit var currentUploadServerUrl:String
 
     private val threadHandler = Handler(Looper.getMainLooper())
@@ -68,11 +72,8 @@
 
             override fun onPageFinished(view: WebView?, url: String?) {
                 super.onPageFinished(view, url)
-
                 view?.requestFocus()
-
                 injectPageLoadFinishedActions()
-
             }
         }
 
@@ -146,6 +147,8 @@
 
         try {
 
+            /*
+
             when (currentUploadServerType) {
                 AppConfig.UPLOADSERVERTYPE_DOUYIN -> {
                     val actionDouyin =
@@ -177,6 +180,8 @@
 
                 }
             }
+
+             */
         }catch (e:Exception){
             e.printStackTrace()
         }
@@ -309,10 +314,9 @@
                     currentUploadServerIndex++
                 }else{
                     lifecycleScope.launch {
-                        Utils.sendVideoUploadedMessage(
-                            requireContext(),
-                            currentUploadVideoInfo.taskId
-                        )
+                        Utils.sendVideoUploadedMessage(currentUploadVideoInfo.taskId) { result, error ->
+                            Toast.makeText(context,error.toString(),Toast.LENGTH_SHORT)
+                        }
                     }
                     startUploadTask()
                 }
@@ -325,7 +329,7 @@
 
     }
 
-    private fun uploadVideoUrlAndWait(taskInfo:Utils.VideoUploadTaskInfo){
+    private fun uploadVideoUrlAndWait(taskInfo: Utils.VideoUploadTaskInfo){
         try{
 
             currentUploadVideoInfo = taskInfo
@@ -370,7 +374,7 @@
 
 
 
-    private suspend fun executeDownloadAndUploadTask(taskInfo:Utils.VideoUploadTaskInfo){
+    private suspend fun executeDownloadAndUploadTask(taskInfo: Utils.VideoUploadTaskInfo){
         Utils.downloadCommonFileToExternalFilesDir(requireContext(),taskInfo.videoUrl,taskInfo.filename+".mp4",false)
         Utils.downloadCommonFileToExternalFilesDir(requireContext(),taskInfo.coverUrl,taskInfo.filename+".png",false)
     }
diff --git a/app/src/main/java/com/shsening/autouploadvideos/UploadListFragment.kt b/app/src/main/java/com/shsening/autouploadvideos/UploadListFragment.kt
new file mode 100644
index 0000000..a2e61fc
--- /dev/null
+++ b/app/src/main/java/com/shsening/autouploadvideos/UploadListFragment.kt
@@ -0,0 +1,144 @@
+package com.shsening.autouploadvideos
+
+import SessionProfile
+import SessionProfileManager
+import android.app.Activity
+import android.app.AlertDialog
+import android.content.Intent
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ArrayAdapter
+import android.widget.Button
+import android.widget.CheckBox
+import android.widget.ListView
+import androidx.fragment.app.Fragment
+import android.widget.TextView
+import com.shsening.autouploadvideos.utils.Utils
+
+class UploadListFragment : Fragment() {
+
+    private lateinit var listView: ListView
+    private lateinit var btnAllTask: View
+    private val REQUEST_CODE = 100
+
+    private val sessionProfiles = mutableListOf<SessionProfile>() // Replace with your real data source
+
+    override fun onCreateView(
+        inflater: LayoutInflater, container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View {
+        val view = inflater.inflate(R.layout.upload_list, container, false)
+
+        listView = view.findViewById(R.id.upload_list_view)
+        btnAllTask = view.findViewById(R.id.btn_all_task)
+
+        setupListView()
+        setupAllTaskButton()
+
+        return view
+    }
+
+    private fun setupListView() {
+        // 娓呯┖閫傞厤鍣�
+        listView.adapter = null
+
+        // 浠� SessionProfileManager 鑾峰彇鎵�鏈夌殑 SessionProfile
+        val sessionProfiles = SessionProfileManager(requireContext()).getAllProfiles()
+
+        // 鑷畾涔夐�傞厤鍣ㄥ疄鐜板垹闄ゆ寜閽姛鑳�
+        val adapter = object : ArrayAdapter<SessionProfile>(
+            requireContext(),
+            android.R.layout.simple_list_item_2,
+            sessionProfiles
+        ) {
+            override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
+                val inflater = LayoutInflater.from(context)
+                val view = convertView ?: inflater.inflate(R.layout.list_item_with_checkbox, parent, false)
+
+                // 鑾峰彇褰撳墠鐨� SessionProfile
+                val sessionProfile = getItem(position)
+
+                // 濉厖鏁版嵁
+                val text1 = view.findViewById<TextView>(android.R.id.text1)
+                val textType = Utils.getSessionProfileValueByPosition(sessionProfile?.type)
+                text1.text = "${sessionProfile?.name} (${textType})"
+
+                val text2 = view.findViewById<TextView>(android.R.id.text2)
+                text2.text = sessionProfile?.lastUploadTime
+
+                // 璁剧疆鍒犻櫎鎸夐挳
+                val deleteButton = view.findViewById<Button>(R.id.deleteButton)
+                deleteButton.setOnClickListener {
+                    val intent = Intent(requireContext(), UploadSessionActivity::class.java)
+                    val sessionProfiles = arrayListOf(sessionProfile) // 鏇挎崲涓哄疄闄呯殑閫夊畾鏁扮粍
+                    intent.putParcelableArrayListExtra("sessionProfiles", sessionProfiles)
+                    startActivityForResult(intent, REQUEST_CODE)
+                }
+
+                return view
+            }
+        }
+
+        // 璁剧疆閫傞厤鍣ㄥ埌 ListView
+        listView.adapter = adapter
+
+    }
+    fun getSelectedSessionProfiles(): ArrayList<SessionProfile> {
+        val selectedProfiles = ArrayList<SessionProfile>()
+
+        // 鑾峰彇 ListView 鐨勯�傞厤鍣�
+        val adapter = listView.adapter as? ArrayAdapter<*>
+        // 纭繚閫傞厤鍣ㄦ纭�
+        if (adapter != null) {
+            // 閬嶅巻 ListView 涓殑鎵�鏈夐」
+            for (i in 0 until adapter.count) {
+                // 鑾峰彇褰撳墠鐨勮鍥�
+                val view = listView.getChildAt(i)
+                // 鑾峰彇 CheckBox 缁勪欢
+                val checkBox = view?.findViewById<CheckBox>(R.id.itemCheckBox)
+
+                // 妫�鏌� CheckBox 鏄惁琚�変腑
+                if (checkBox?.isChecked == true) {
+                    // 鑾峰彇瀵瑰簲鐨� SessionProfile 瀵硅薄
+                    val sessionProfile = adapter.getItem(i) as? SessionProfile
+                    // 灏嗛�変腑鐨� SessionProfile 娣诲姞鍒扮粨鏋滃垪琛ㄤ腑
+                    sessionProfile?.let {
+                        selectedProfiles.add(it)
+                    }
+                }
+            }
+        }
+
+        return selectedProfiles
+    }
+
+
+    // 鎺ユ敹鍒� Activity 杩斿洖缁撴灉鏃跺埛鏂� Fragment
+    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+        super.onActivityResult(requestCode, resultCode, data)
+        if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK) {
+            // 鍒锋柊 Fragment 鍐呭
+            setupListView()
+        }
+    }
+
+    private fun setupAllTaskButton() {
+        btnAllTask.setOnClickListener {
+
+            var selected = getSelectedSessionProfiles()
+            if (selected.isEmpty()){
+                    AlertDialog.Builder(requireContext())
+                        .setTitle("鎻愮ず")
+                        .setMessage("璇疯嚦灏戦�夋嫨涓�涓」鐩紒")
+                        .setPositiveButton("纭畾", null)
+                        .show()
+            }else {
+                val intent = Intent(requireContext(), UploadSessionActivity::class.java)
+                intent.putParcelableArrayListExtra("sessionProfiles", selected)
+                startActivityForResult(intent, REQUEST_CODE)
+            }
+        }
+    }
+}
diff --git a/app/src/main/java/com/shsening/autouploadvideos/UploadSessionActivity.kt b/app/src/main/java/com/shsening/autouploadvideos/UploadSessionActivity.kt
new file mode 100644
index 0000000..b06cd33
--- /dev/null
+++ b/app/src/main/java/com/shsening/autouploadvideos/UploadSessionActivity.kt
@@ -0,0 +1,266 @@
+package com.shsening.autouploadvideos
+
+import CookieHelper
+import Profile
+import SessionProfile
+import SessionProfileManager
+import android.app.Activity
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.util.Log
+import android.view.View
+import android.webkit.CookieManager
+import android.webkit.ValueCallback
+import android.webkit.WebChromeClient
+import android.webkit.WebView
+import android.webkit.WebViewClient
+import android.widget.ArrayAdapter
+import android.widget.Button
+import android.widget.EditText
+import android.widget.LinearLayout
+import android.widget.ProgressBar
+import android.widget.Spinner
+import android.widget.Switch
+import android.widget.TextView
+import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.FileProvider
+import com.shsening.autouploadvideos.AppConfig.Companion.SESSION_PROFILE_PALTFORM_LISTS
+import com.shsening.autouploadvideos.action.ActionDouyin
+import com.shsening.autouploadvideos.action.ActionKuaishou
+import com.shsening.autouploadvideos.action.ActionShipinhao
+import com.shsening.autouploadvideos.utils.DownloadHelper
+import com.shsening.autouploadvideos.utils.DownloadReceiver
+import com.shsening.autouploadvideos.utils.Utils
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import okhttp3.Call
+import okhttp3.Callback
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.Response
+import org.json.JSONArray
+import java.io.File
+import java.io.IOException
+import java.util.LinkedList
+import java.util.Queue
+import java.util.UUID
+
+class UploadSessionActivity : AppCompatActivity() {
+
+    private lateinit var sessionProfileManager: SessionProfileManager
+    lateinit var sessionProfileWebView:SessionProfileWebView
+
+    private lateinit var uploadSessionText :TextView
+    private lateinit var downloadHelper:DownloadHelper
+
+    private val uploadTaskQueue: Queue<Utils.VideoUploadTaskInfo> = LinkedList() // 瀛樺偍涓婁紶浠诲姟闃熷垪
+
+    private lateinit var sessionProfiles: java.util.ArrayList<SessionProfile>
+
+    private var last_uploaded_task_id:String = ""
+
+    private val threadHandler = Handler(Looper.getMainLooper())
+
+    private lateinit var activityReference: UploadSessionActivity
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.upload_session)
+
+        activityReference = this
+        // 鍒濆鍖� SessionProfileManager
+        sessionProfileManager = SessionProfileManager(this)
+        //downloadReceiver = DownloadReceiver(this,)
+        uploadSessionText = findViewById(R.id.uploadSessionText)
+        sessionProfileWebView = findViewById(R.id.uploadSessionWebView)
+        // 鑾峰彇浼犻�掔殑 SessionProfile 鏁扮粍
+        sessionProfiles =
+            intent.getParcelableArrayListExtra<SessionProfile>("sessionProfiles")
+                ?: arrayListOf()
+        if (sessionProfiles != null) {
+            for (profile in sessionProfiles) {
+                processProfile(profile)
+            }
+        } else {
+            Toast.makeText(this, "鏈帴鏀跺埌浠讳綍 Profile 鏁版嵁", Toast.LENGTH_SHORT).show()
+        }
+        downloadHelper = DownloadHelper(this)
+
+
+
+        //sessionProfileWebView.setInitialScale(75) // 鍒濆缂╂斁姣斾緥
+
+        sessionProfileWebView.webViewClient = object : WebViewClient() {
+            override fun onPageStarted(
+                view: WebView?,
+                url: String?,
+                favicon: android.graphics.Bitmap?
+            ) {
+                super.onPageStarted(view, url, favicon)
+            }
+            override fun onPageFinished(view: WebView?, url: String?) {
+                super.onPageFinished(view, url)
+                view?.requestFocus() // 纭繚 WebView 鑾峰彇鐒︾偣
+                //inject action
+                val currentTask = uploadTaskQueue.peek()
+                when (currentTask?.platform?.name) {
+                    "鎶栭煶" -> {
+                        val action =
+                            ActionDouyin(activityReference, threadHandler, currentTask)
+                        action.checkIfContentLoaded()
+                    }
+                    "蹇墜" -> {
+                        val action =
+                            ActionKuaishou(activityReference, threadHandler, currentTask)
+                        action.checkIfContentLoaded()
+                    }
+                    "瑙嗛鍙�" -> {
+                        val action =
+                            ActionShipinhao(activityReference, threadHandler, currentTask)
+                        action.checkIfContentLoaded()
+                    }
+                }
+                url?.let{
+                    Log.e("shsening", url)
+                    try {
+                        val cookies = CookieManager.getInstance().getCookie(url)
+                        if (cookies != null) {
+                            CookieHelper.saveSessionProfileUrlCookies(
+                                activityReference,
+                                currentTask.sessionProfileId!!,
+                                url,
+                                cookies
+                            )
+                        } else {
+                            Log.w("shsening", "No cookies found for URL: $url")
+                        }
+                    } catch (e: java.lang.Exception) {
+                        Log.e("CookieHelper", "Failed to get cookies: ", e)
+                    }
+                }
+            }
+        }
+        sessionProfileWebView.webChromeClient = object : WebChromeClient() {
+            override fun onShowFileChooser(
+                webView: WebView,
+                filePathCallback: ValueCallback<Array<Uri>>,
+                fileChooserParams: FileChooserParams
+            ): Boolean {
+                try {
+                    var mFilePathCallback: ValueCallback<Array<Uri>>? = filePathCallback
+                    // 閫夋嫨鐗瑰畾鐨勬枃浠�
+                    val currentTask = uploadTaskQueue.peek()
+                    val download_dir = File(getExternalFilesDir(null), currentTask.sessionProfileId)
+                    val file = File(download_dir, currentTask.filename + ".mp4")
+                    val uri: Uri =
+                        FileProvider.getUriForFile(activityReference, AppConfig.FILE_PROVIDER, file)
+
+                    mFilePathCallback?.onReceiveValue(arrayOf(uri))
+                    return true
+                }catch(e:Exception) {
+                    return false
+                }
+            }
+            override fun onShowCustomView(view: View?, callback: CustomViewCallback?) {
+                super.onShowCustomView(view, callback)
+                view?.requestFocus()
+            }
+        }
+        sessionProfileWebView.isFocusableInTouchMode = true
+
+        findViewById<Button>(R.id.btn_upload_back).setOnClickListener {
+            finish()
+        }
+    }
+
+    private fun processProfile(profile:SessionProfile){
+        val downloadDir = File(getExternalFilesDir(null), profile.id) // 鑾峰彇搴旂敤鐨勫閮ㄥ瓨鍌ㄧ洰褰曪紝骞舵寚瀹� sessionid 瀛愮洰褰�
+
+        Utils.fetchTasksBySessionProfile(profile, object:Utils.FetchTasksCallback {
+            override fun onTasksFetched(uploadTaskList: MutableList<Utils.VideoUploadTaskInfo>) {
+                uploadTaskList.forEach { task ->
+                    downloadHelper.downloadSingleFile(task.videoUrl, File(downloadDir,task.filename+".mp4"))
+                    downloadHelper.downloadSingleFile(task.coverUrl, File(downloadDir,task.filename+".png"))
+                    profile.getValidProfileNames().forEach{ platform ->
+                        var taskInfo = Utils.VideoUploadTaskInfo(task.taskId,
+                            task.title,
+                            task.description,
+                            task.datetime,
+                            task.videoUrl,
+                            task.coverUrl,
+                            task.filename,
+                            profile.id,
+                            profile.name,
+                            SESSION_PROFILE_PALTFORM_LISTS.find { it.name == platform }
+                        )
+                        uploadTaskQueue.offer(taskInfo)
+                    }
+
+                }
+                Handler(Looper.getMainLooper()).postDelayed({
+                    checkAndStartNextTask() // 寤舵椂绛夊緟涓嬭浇浠诲姟
+                }, 3000)
+            }
+        })
+    }
+    fun checkAndStartNextTask() {
+        if (uploadTaskQueue.isNotEmpty()) {
+            val nextTask = uploadTaskQueue.poll()
+            nextTask?.let {
+                nextTask.sessionProfileId?.let { sessionId ->
+                    runOnUiThread {
+                        if (last_uploaded_task_id != "" && last_uploaded_task_id != nextTask.taskId) {
+                                Utils.sendVideoUploadedMessage(last_uploaded_task_id) { result, error ->
+                                    Handler(Looper.getMainLooper()).post {
+                                        Toast.makeText(
+                                            activityReference,
+                                            error?.message,
+                                            Toast.LENGTH_SHORT
+                                        )
+                                    }
+                            }
+                        } else {
+                            last_uploaded_task_id = nextTask.taskId
+                        }
+                        nextTask.platform?.let {
+                                sessionProfileWebView.loadSessionProfileCookies(sessionId)
+                                sessionProfileWebView.loadUrl(it.url)
+                                Handler(Looper.getMainLooper()).post {
+                                uploadSessionText.text = "浠诲姟锛�${nextTask.sessionProfileName}. 鍓╀綑:${uploadTaskQueue.size+1} "
+                                }
+                        };
+                    }
+                }
+            }
+        }else{
+            Handler(Looper.getMainLooper()).post {
+                uploadSessionText.text = "浠诲姟宸茬粨鏉熴��"
+            }
+            Handler(Looper.getMainLooper()).postDelayed({
+                if (sessionProfiles != null) {
+                    for (profile in sessionProfiles) {
+                        updateSessionProfileLastUploadTime(profile)
+                    }
+                }
+                finish()
+            }, 2000)
+
+        }
+    }
+
+
+    private fun updateSessionProfileLastUploadTime(sessionProfile: SessionProfile) {
+        sessionProfile.lastUploadTime = Utils.getCurrentTimeString()
+        sessionProfileManager.addOrUpdateSessionProfile(sessionProfile)
+        sessionProfileManager.saveToFile()
+    }
+
+    override fun onDestroy() {
+        super.onDestroy()
+    }
+}
diff --git a/app/src/main/java/com/shsening/autouploadvideos/WebviewUtils.kt b/app/src/main/java/com/shsening/autouploadvideos/WebviewUtils.kt
index c2f0b26..e6cb6fb 100644
--- a/app/src/main/java/com/shsening/autouploadvideos/WebviewUtils.kt
+++ b/app/src/main/java/com/shsening/autouploadvideos/WebviewUtils.kt
@@ -67,7 +67,5 @@
             }
     """.trimIndent()
         webView.evaluateJavascript(clickScript, null)
-
     }
-
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/shsening/autouploadvideos/ActionDouyin.kt b/app/src/main/java/com/shsening/autouploadvideos/action/ActionDouyin.kt
similarity index 69%
rename from app/src/main/java/com/shsening/autouploadvideos/ActionDouyin.kt
rename to app/src/main/java/com/shsening/autouploadvideos/action/ActionDouyin.kt
index 2f2d13a..9e029b1 100644
--- a/app/src/main/java/com/shsening/autouploadvideos/ActionDouyin.kt
+++ b/app/src/main/java/com/shsening/autouploadvideos/action/ActionDouyin.kt
@@ -1,15 +1,17 @@
-package com.shsening.autouploadvideos
+package com.shsening.autouploadvideos.action
 
 
 import android.app.Instrumentation
-import android.content.Context
 import android.os.SystemClock
 import android.os.Handler
+import com.shsening.autouploadvideos.UploadSessionActivity
+import com.shsening.autouploadvideos.utils.Utils
+import com.shsening.autouploadvideos.WebviewUtils
 
-class ActionDouyin (private var fragment:UploadFragment, private var context:Context, private var threadHandler: Handler, private var videoInfo:Utils.VideoUploadTaskInfo){
+class ActionDouyin (private var activity: UploadSessionActivity, private var threadHandler: Handler, private var videoInfo: Utils.VideoUploadTaskInfo) :PlatformActionInterface{
 
 
-    private var webView = fragment.webView
+    private var webView = activity.sessionProfileWebView
 
 
     var jsCode_CheckContentLoaded = """
@@ -25,16 +27,39 @@
 
 
     private fun updatePostDescription(){
-        WebviewUtils.addValueToInput(webView,"#root > div > div > div.content-body-v8tuJQ > div.form-kSES6A > div.publish-mention-wrapper-LWv5ed > div.editor-container-zRPSAi > div > div > div > div:nth-child(1) > div > div > input",videoInfo.title)
+        WebviewUtils.addValueToInput(
+            webView,
+            "#root > div > div > div.content-body-v8tuJQ > div.form-kSES6A > div.publish-mention-wrapper-LWv5ed > div.editor-container-zRPSAi > div > div > div > div:nth-child(1) > div > div > input",
+            videoInfo.title
+        )
 
-        WebviewUtils.addValueToDiv(webView,"#root > div > div > div.content-body-v8tuJQ > div.form-kSES6A > div.publish-mention-wrapper-LWv5ed > div.editor-container-zRPSAi > div > div > div > div.outerdocbody.editor-kit-outer-container > div",videoInfo.description)
+        WebviewUtils.addValueToDiv(
+            webView,
+            "#root > div > div > div.content-body-v8tuJQ > div.form-kSES6A > div.publish-mention-wrapper-LWv5ed > div.editor-container-zRPSAi > div > div > div > div.outerdocbody.editor-kit-outer-container > div",
+            videoInfo.description
+        )
 
-        WebviewUtils.simpleElementClick(webView,"#root > div > div > div.content-body-v8tuJQ > div.form-kSES6A > div.publish-mention-wrapper-LWv5ed > div:nth-child(3) > div > div.activity-list-container-AZzfdV > div:nth-child(1)")
-        WebviewUtils.simpleElementClick(webView,"#root > div > div > div.content-body-v8tuJQ > div.form-kSES6A > div.publish-mention-wrapper-LWv5ed > div:nth-child(3) > div > div.activity-list-container-AZzfdV > div:nth-child(2)")
+        WebviewUtils.simpleElementClick(
+            webView,
+            "#root > div > div > div.content-body-v8tuJQ > div.form-kSES6A > div.publish-mention-wrapper-LWv5ed > div:nth-child(3) > div > div.activity-list-container-AZzfdV > div:nth-child(1)"
+        )
+        WebviewUtils.simpleElementClick(
+            webView,
+            "#root > div > div > div.content-body-v8tuJQ > div.form-kSES6A > div.publish-mention-wrapper-LWv5ed > div:nth-child(3) > div > div.activity-list-container-AZzfdV > div:nth-child(2)"
+        )
 
-        WebviewUtils.simpleElementClick(webView,"#root > div > div > div.content-body-v8tuJQ > div.form-kSES6A > div.content-upload-new > div > div.recommendContainer-HXvL9W > div.recommendDisplay-ifUYki > div > div:nth-child(1) > div")
-        WebviewUtils.simpleElementClick(webView,"#root > div > div > div.content-body-v8tuJQ > div.form-kSES6A > div.download-content-Lci5tL > div > label:nth-child(2)")
-        WebviewUtils.simpleElementClick(webView,"#root > div > div > div.content-body-v8tuJQ > div.form-kSES6A > div.publish-settings-WtW_ZW > div.schedule-part-V615Zn > div.row-suTOx_ > label:nth-child(2)")
+        WebviewUtils.simpleElementClick(
+            webView,
+            "#root > div > div > div.content-body-v8tuJQ > div.form-kSES6A > div.content-upload-new > div > div.recommendContainer-HXvL9W > div.recommendDisplay-ifUYki > div > div:nth-child(1) > div"
+        )
+        WebviewUtils.simpleElementClick(
+            webView,
+            "#root > div > div > div.content-body-v8tuJQ > div.form-kSES6A > div.download-content-Lci5tL > div > label:nth-child(2)"
+        )
+        WebviewUtils.simpleElementClick(
+            webView,
+            "#root > div > div > div.content-body-v8tuJQ > div.form-kSES6A > div.publish-settings-WtW_ZW > div.schedule-part-V615Zn > div.row-suTOx_ > label:nth-child(2)"
+        )
 
         addValueToDatePickerInput(true,"#root > div > div > div.content-body-v8tuJQ > div.form-kSES6A > div.publish-settings-WtW_ZW > div.schedule-part-V615Zn > div.row-suTOx_ > div.date-picker-ioPchj > div > div",videoInfo.datetime)
 
@@ -45,7 +70,7 @@
     }
 
 
-    fun checkIfContentLoaded() {
+    override fun checkIfContentLoaded() {
         webView.postDelayed({
             webView.evaluateJavascript(jsCode_CheckContentLoaded) { result ->
                 if (result == "true") {
@@ -60,7 +85,7 @@
     }
 
     private fun startToPublishVideo(){
-        WebviewUtils.simpleElementClick(webView,jsPath_PublishVideo)
+        WebviewUtils.simpleElementClick(webView, jsPath_PublishVideo)
 
         checkVideoPublishFinished()
     }
@@ -88,7 +113,7 @@
                 if (result == "true") {
 
                     // video published successfully!!!
-                    fragment.startUploadSingleTask()
+                    activity.checkAndStartNextTask()
 
 
                 } else {
@@ -108,7 +133,7 @@
 
         var dpPanelText = datetimes[0].toString()+"骞� "+datetimes[1].toString()+"鏈�";
 
-        var dateRowColum = Utils.getDatePosition(datetimes[0],datetimes[1],datetimes[2])?:return;
+        var dateRowColum = Utils.getDatePosition(datetimes[0], datetimes[1], datetimes[2]) ?:return;
 
         val jsCode = """
        try {
@@ -144,7 +169,7 @@
 
     private fun simulateSwipeAndUploadVideo() {
         val instrumentation = Instrumentation()
-        val displayMetrics = context.resources.displayMetrics
+        val displayMetrics = activity.resources.displayMetrics
         val width = displayMetrics.widthPixels
         val height = displayMetrics.heightPixels
 
diff --git a/app/src/main/java/com/shsening/autouploadvideos/ActionKuaishou.kt b/app/src/main/java/com/shsening/autouploadvideos/action/ActionKuaishou.kt
similarity index 79%
rename from app/src/main/java/com/shsening/autouploadvideos/ActionKuaishou.kt
rename to app/src/main/java/com/shsening/autouploadvideos/action/ActionKuaishou.kt
index 91e05c0..9fbf44d 100644
--- a/app/src/main/java/com/shsening/autouploadvideos/ActionKuaishou.kt
+++ b/app/src/main/java/com/shsening/autouploadvideos/action/ActionKuaishou.kt
@@ -1,15 +1,19 @@
-package com.shsening.autouploadvideos
+package com.shsening.autouploadvideos.action
 
 
 import android.app.Instrumentation
 import android.content.Context
 import android.os.SystemClock
 import android.os.Handler
+import com.shsening.autouploadvideos.UploadFragment
+import com.shsening.autouploadvideos.UploadSessionActivity
+import com.shsening.autouploadvideos.utils.Utils
+import com.shsening.autouploadvideos.WebviewUtils
 
-class ActionKuaishou (private var fragment:UploadFragment, private var context:Context, private var threadHandler: Handler, private var videoInfo:Utils.VideoUploadTaskInfo){
+class ActionKuaishou (private var activity: UploadSessionActivity, private var threadHandler: Handler, private var videoInfo: Utils.VideoUploadTaskInfo) :PlatformActionInterface{
 
 
-    private var webView = fragment.webView
+    private var webView = activity.sessionProfileWebView
 
 
     var jsCode_CheckContentLoaded = """
@@ -29,16 +33,25 @@
      */
     private fun updatePostDescription(){
 
-        WebviewUtils.addValueToDiv(webView,"#work-description-edit",videoInfo.description)
+        WebviewUtils.addValueToDiv(webView, "#work-description-edit", videoInfo.description)
 
         // do not allow download
-        WebviewUtils.simpleElementClick(webView,"#setting-tours > div:nth-child(2) > div > label:nth-child(2)")
+        WebviewUtils.simpleElementClick(
+            webView,
+            "#setting-tours > div:nth-child(2) > div > label:nth-child(2)"
+        )
 
         // do not show same city
-        WebviewUtils.simpleElementClick(webView,"#setting-tours > div:nth-child(2) > div > label:nth-child(3)")
+        WebviewUtils.simpleElementClick(
+            webView,
+            "#setting-tours > div:nth-child(2) > div > label:nth-child(3)"
+        )
 
         //Scheduled publish
-        WebviewUtils.simpleElementClick(webView,"#setting-tours > div:nth-child(4) > div > div > label:nth-child(2)")
+        WebviewUtils.simpleElementClick(
+            webView,
+            "#setting-tours > div:nth-child(4) > div > div > label:nth-child(2)"
+        )
 
         addValueToDatePickerInput(true,"#setting-tours > div:nth-child(4) > div > div:nth-child(2) > div > div > input",videoInfo.datetime)
         // 鍦ㄤ富绾跨▼涓缃欢杩熸墽琛�
@@ -48,7 +61,7 @@
     }
 
 
-    fun checkIfContentLoaded() {
+    override fun checkIfContentLoaded() {
         webView.postDelayed({
             webView.evaluateJavascript(jsCode_CheckContentLoaded) { result ->
                 if (result == "true") {
@@ -63,7 +76,7 @@
     }
 
     private fun startToPublishVideo(){
-        WebviewUtils.simpleElementClick(webView,jsPath_PublishVideo)
+        WebviewUtils.simpleElementClick(webView, jsPath_PublishVideo)
         checkVideoPublishFinished()
     }
     private fun checkVideoUploadFinished(){
@@ -87,7 +100,7 @@
             webView.evaluateJavascript(jsCode_PublishVideo_Finished) { result ->
                 if (result == "true") {
                     // video published successfully!!!
-                    fragment.startUploadSingleTask()
+                    activity.checkAndStartNextTask()
                 } else {
                     // 鍏冪礌涓嶅瓨鍦紝1绉掑悗鍐嶆妫�鏌�
                     webView.postDelayed({
@@ -103,9 +116,9 @@
 
         var datetimes = Utils.validateAndReturnDateTime(targetValue) ?: return
 
-        var dpPanelText = datetimes[0].toString()+"骞�"+Utils.getMonthAbbreviation(datetimes[1]);
+        var dpPanelText = datetimes[0].toString()+"骞�"+ Utils.getMonthAbbreviation(datetimes[1]);
 
-        var dateRowColum = Utils.getDatePosition(datetimes[0],datetimes[1],datetimes[2])?:return;
+        var dateRowColum = Utils.getDatePosition(datetimes[0], datetimes[1], datetimes[2]) ?:return;
 
         val jsCode = """
        try {
@@ -149,7 +162,7 @@
 
     private fun simulateSwipeAndUploadVideo() {
         val instrumentation = Instrumentation()
-        val displayMetrics = context.resources.displayMetrics
+        val displayMetrics = activity.resources.displayMetrics
         val width = displayMetrics.widthPixels
         val height = displayMetrics.heightPixels
 
@@ -160,7 +173,7 @@
         Thread {
             Utils.instrumentationSwipe(instrumentation, startX, y, endX, y)
             SystemClock.sleep(500)
-            Utils.instrumentationClick(instrumentation, width *4/5f, height *2/ 3f)
+            Utils.instrumentationClick(instrumentation, width * 4 / 5f, height * 2 / 3f)
             // back to main thread
             threadHandler.post {
                 checkVideoUploadFinished()
diff --git a/app/src/main/java/com/shsening/autouploadvideos/ActionShipinhao.kt b/app/src/main/java/com/shsening/autouploadvideos/action/ActionShipinhao.kt
similarity index 78%
rename from app/src/main/java/com/shsening/autouploadvideos/ActionShipinhao.kt
rename to app/src/main/java/com/shsening/autouploadvideos/action/ActionShipinhao.kt
index b7e2c05..34c6430 100644
--- a/app/src/main/java/com/shsening/autouploadvideos/ActionShipinhao.kt
+++ b/app/src/main/java/com/shsening/autouploadvideos/action/ActionShipinhao.kt
@@ -1,15 +1,18 @@
-package com.shsening.autouploadvideos
+package com.shsening.autouploadvideos.action
 
 
 import android.app.Instrumentation
 import android.content.Context
 import android.os.SystemClock
 import android.os.Handler
+import com.shsening.autouploadvideos.UploadFragment
+import com.shsening.autouploadvideos.UploadSessionActivity
+import com.shsening.autouploadvideos.utils.Utils
+import com.shsening.autouploadvideos.WebviewUtils
 
-class ActionShipinhao (private var fragment:UploadFragment, private var context:Context, private var threadHandler: Handler, private var videoInfo:Utils.VideoUploadTaskInfo){
+class ActionShipinhao (private var activity: UploadSessionActivity, private var threadHandler: Handler, private var videoInfo: Utils.VideoUploadTaskInfo) :PlatformActionInterface{
 
-
-    private var webView = fragment.webView
+    private var webView = activity.sessionProfileWebView
 
 
     var jsCode_CheckContentLoaded = """
@@ -28,11 +31,18 @@
      * Title,description(including # and @ ) publish datetime etc
      */
     private fun updatePostDescription(){
-        WebviewUtils.addValueToDiv(webView,"#container-wrap > div.container-center > div > div > div.main-body-wrap.post-create > div.main-body > div > div.post-edit-wrap.material-edit-wrap > div.form > div:nth-child(2) > div.form-item-body > div > div.input-editor",videoInfo.description)
+        WebviewUtils.addValueToDiv(
+            webView,
+            "#container-wrap > div.container-center > div > div > div.main-body-wrap.post-create > div.main-body > div > div.post-edit-wrap.material-edit-wrap > div.form > div:nth-child(2) > div.form-item-body > div > div.input-editor",
+            videoInfo.description
+        )
 
 
         // publish later radiobox
-        WebviewUtils.simpleElementClick(webView,"#container-wrap > div.container-center > div > div > div.main-body-wrap.post-create > div.main-body > div > div.post-edit-wrap.material-edit-wrap > div.form > div.post-time-wrap > div:nth-child(1) > div.form-item-body > div > label:nth-child(2)")
+        WebviewUtils.simpleElementClick(
+            webView,
+            "#container-wrap > div.container-center > div > div > div.main-body-wrap.post-create > div.main-body > div > div.post-edit-wrap.material-edit-wrap > div.form > div.post-time-wrap > div:nth-child(1) > div.form-item-body > div > label:nth-child(2)"
+        )
 
         addValueToDatePickerInput(true,"#container-wrap > div.container-center > div > div > div.main-body-wrap.post-create > div.main-body > div > div.post-edit-wrap.material-edit-wrap > div.form > div.post-time-wrap > div:nth-child(2) > div.form-item-body > dl > dd",videoInfo.datetime)
 
@@ -44,7 +54,7 @@
     }
 
 
-    fun checkIfContentLoaded() {
+    override fun checkIfContentLoaded() {
         webView.postDelayed({
             webView.evaluateJavascript(jsCode_CheckContentLoaded) { result ->
                 if (result == "true") {
@@ -59,7 +69,7 @@
     }
 
     private fun startToPublishVideo(){
-        WebviewUtils.simpleElementClick(webView,jsPath_PublishVideo)
+        WebviewUtils.simpleElementClick(webView, jsPath_PublishVideo)
         checkVideoPublishFinished()
     }
     private fun checkVideoUploadFinished(){
@@ -83,7 +93,7 @@
             webView.evaluateJavascript(jsCode_PublishVideo_Finished) { result ->
                 if (result == "true") {
                     // video published successfully!!!
-                    fragment.startUploadSingleTask()
+                    activity.checkAndStartNextTask()
                 } else {
                     // 鍏冪礌涓嶅瓨鍦紝1绉掑悗鍐嶆妫�鏌�
                     webView.postDelayed({
@@ -101,7 +111,7 @@
 
         var dpPanelText = datetimes[0].toString()+"骞� "+datetimes[1].toString()+"鏈�";
 
-        var dateRowColum = Utils.getDatePosition(datetimes[0],datetimes[1],datetimes[2])?:return;
+        var dateRowColum = Utils.getDatePosition(datetimes[0], datetimes[1], datetimes[2]) ?:return;
 
         val jsCode = """
        try {
@@ -136,7 +146,7 @@
 
     private fun simulateSwipeAndUploadVideo() {
         val instrumentation = Instrumentation()
-        val displayMetrics = context.resources.displayMetrics
+        val displayMetrics = activity.resources.displayMetrics
         val width = displayMetrics.widthPixels
         val height = displayMetrics.heightPixels
 
@@ -147,7 +157,7 @@
         Thread {
             Utils.instrumentationSwipe(instrumentation, startX, y, endX, y)
             SystemClock.sleep(500)
-            Utils.instrumentationClick(instrumentation, width *4/5f, height  / 2f)
+            Utils.instrumentationClick(instrumentation, width * 4 / 5f, height / 2f)
             // back to main thread
             threadHandler.post {
                 checkVideoUploadFinished()
diff --git a/app/src/main/java/com/shsening/autouploadvideos/action/PlatformActionInterface.kt b/app/src/main/java/com/shsening/autouploadvideos/action/PlatformActionInterface.kt
new file mode 100644
index 0000000..c2f86ce
--- /dev/null
+++ b/app/src/main/java/com/shsening/autouploadvideos/action/PlatformActionInterface.kt
@@ -0,0 +1,7 @@
+package com.shsening.autouploadvideos.action
+
+interface PlatformActionInterface {
+
+    fun checkIfContentLoaded()
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/shsening/autouploadvideos/utils/BroadcastReceiver.kt b/app/src/main/java/com/shsening/autouploadvideos/utils/BroadcastReceiver.kt
new file mode 100644
index 0000000..5df0b7b
--- /dev/null
+++ b/app/src/main/java/com/shsening/autouploadvideos/utils/BroadcastReceiver.kt
@@ -0,0 +1,28 @@
+package com.shsening.autouploadvideos.utils
+
+import android.app.DownloadManager
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.widget.Toast
+
+class DownloadReceiver(private val context: Context,private val downloadHelper: DownloadHelper) : BroadcastReceiver() {
+
+    init {
+        context.registerReceiver(this, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
+    }
+    override fun onReceive(context: Context, intent: Intent) {
+        val action = intent.action
+        if (DownloadManager.ACTION_DOWNLOAD_COMPLETE == action) {
+            val downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
+            if (downloadId != -1L) {
+                // downoad finished
+            }
+        }
+    }
+
+    fun unregister() {
+        context.unregisterReceiver(this)
+    }
+}
diff --git a/app/src/main/java/com/shsening/autouploadvideos/utils/DownloadHelper.kt b/app/src/main/java/com/shsening/autouploadvideos/utils/DownloadHelper.kt
new file mode 100644
index 0000000..7308955
--- /dev/null
+++ b/app/src/main/java/com/shsening/autouploadvideos/utils/DownloadHelper.kt
@@ -0,0 +1,41 @@
+package com.shsening.autouploadvideos.utils
+
+import android.app.DownloadManager
+import android.content.Context
+import android.net.Uri
+import android.os.Environment
+import android.widget.Toast
+import java.io.File
+
+class DownloadHelper(private val context: Context) {
+
+    private val downloadManager =
+        context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
+
+    fun downloadSingleFile(fileUrl:String,fileUri:File) {
+            try {
+                if (fileUri.exists()) {
+                    return
+                }
+                // 纭繚鐩爣鏂囦欢鎵�鍦ㄧ殑鐩綍瀛樺湪
+                val parentDir = fileUri.parentFile
+                if (parentDir != null && !parentDir.exists()) {
+                    parentDir.mkdirs()  // 鍒涘缓鐩綍
+                }
+                val request = DownloadManager.Request(Uri.parse(fileUrl)).apply {
+                    setTitle("Downloading ${fileUri.name}")
+                    setDescription("Downloading file...")
+                    .setDestinationUri(Uri.fromFile(fileUri)) // 璁剧疆涓嬭浇鏂囦欢淇濆瓨璺緞
+                    setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
+                    setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE)
+
+                }
+                // 灏嗕笅杞借姹傚姞鍏ラ槦鍒�
+                downloadManager.enqueue(request)
+
+            } catch (e: Exception) {
+                e.printStackTrace()
+                Toast.makeText(context, "Failed to download: $fileUrl", Toast.LENGTH_SHORT).show()
+            }
+    }
+}
diff --git a/app/src/main/java/com/shsening/autouploadvideos/Utils.kt b/app/src/main/java/com/shsening/autouploadvideos/utils/Utils.kt
similarity index 65%
rename from app/src/main/java/com/shsening/autouploadvideos/Utils.kt
rename to app/src/main/java/com/shsening/autouploadvideos/utils/Utils.kt
index c1d3a9e..ed18a16 100644
--- a/app/src/main/java/com/shsening/autouploadvideos/Utils.kt
+++ b/app/src/main/java/com/shsening/autouploadvideos/utils/Utils.kt
@@ -1,13 +1,17 @@
-package com.shsening.autouploadvideos
+package com.shsening.autouploadvideos.utils
 
 
+import SessionProfile
 import android.app.Instrumentation
 import android.content.Context
 import android.content.Intent
 import android.os.SystemClock
 import android.view.MotionEvent
+import android.webkit.CookieManager
 import android.widget.Toast
 import androidx.core.content.FileProvider
+import com.shsening.autouploadvideos.AppConfig
+import com.shsening.autouploadvideos.PlatformItem
 import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.withContext
@@ -16,11 +20,15 @@
 import okhttp3.OkHttpClient
 import okhttp3.Request
 import okhttp3.Response
+import org.json.JSONArray
 import org.json.JSONObject
 import java.io.File
 import java.io.IOException
 import java.io.Serializable
+import java.text.SimpleDateFormat
 import java.util.Calendar
+import java.util.Date
+import java.util.Locale
 
 object Utils {
     data class AppUpdateInfo(
@@ -37,7 +45,10 @@
         val datetime: String,
         val videoUrl: String,
         val coverUrl: String,
-        var filename: String = generateFilename(datetime)
+        var filename: String = generateFilename(datetime),
+        var sessionProfileId: String? =null,
+        var sessionProfileName: String? =null,
+        var platform: PlatformItem? =null
     ) : Serializable {
 
         companion object {
@@ -150,26 +161,37 @@
 
         return arrayOf(row, column) // 杩斿洖鏁扮粍
     }
-    suspend fun sendVideoUploadedMessage(context: Context,taskId: String): Boolean {
+    fun sendVideoUploadedMessage(taskId: String, callback: (Boolean, Exception?) -> Unit) {
         try {
             val client = OkHttpClient()
             val request = Request.Builder()
                 .url(AppConfig.URL_CONFIRM_TASK_UPLOADED + taskId)
                 .build()
+            // 寮傛鎵ц缃戠粶璇锋眰
+            client.newCall(request).enqueue(object : okhttp3.Callback {
+                override fun onFailure(call: okhttp3.Call, e: IOException) {
+                    // 璇锋眰澶辫触锛岃繑鍥為敊璇�
+                    callback(false, e)
+                }
 
-            return withContext(Dispatchers.IO) {
-
-                val response = client.newCall(request).execute()
-                if (!response.isSuccessful) throw IOException("Unexpected code $response")
-                val json = JSONObject(response.body?.string() ?: "")
-
-                json.getBoolean("result")
-            }
-        }catch(e:Exception){
+                override fun onResponse(call: okhttp3.Call, response: okhttp3.Response) {
+                    try {
+                        val json = JSONObject(response.body?.string() ?: "")
+                        val result = json.getString("msg")
+                        // 鎴愬姛鍥炶皟
+                        callback(true, Exception(result))
+                    } catch (e: Exception) {
+                        // 澶勭悊瑙f瀽閿欒
+                        callback(false, e)
+                    } finally {
+                        response.close()
+                    }
+                }
+            })
+        } catch (e: Exception) {
             e.printStackTrace()
-
-            return false
-
+            // 澶勭悊鍏朵粬寮傚父
+            callback(false, e)
         }
     }
 
@@ -203,6 +225,56 @@
 
         }
     }
+    interface FetchTasksCallback {
+        fun onTasksFetched(uploadTaskList: MutableList<Utils.VideoUploadTaskInfo>)
+    }
+    interface UploadCallback {
+        fun onSuccess()
+        fun onError()
+    }
+
+    fun fetchTasksBySessionProfile(profile: SessionProfile, callback: FetchTasksCallback) {
+        val uploadTaskList: MutableList<Utils.VideoUploadTaskInfo> = mutableListOf()
+
+        val client = OkHttpClient()
+        val request = Request.Builder()
+            .url(AppConfig.URL_CHECK_CLIENT_TASKS + AppConfig.CLIENT_ANDROID_ID + "&sessionprofile=" + profile.id + "&videotype=" + profile.type) // 鏇挎崲涓轰綘鐨勪换鍔″湴鍧�
+            .build()
+
+        client.newCall(request).enqueue(object : Callback {
+            override fun onFailure(call: Call, e: IOException) {
+                e.printStackTrace()
+                // 鍙互鍦ㄨ繖閲岄�氱煡璋冪敤鑰呭嚭閿�
+            }
+
+            override fun onResponse(call: Call, response: Response) {
+                response.use {
+                    if (!response.isSuccessful) throw IOException("Unexpected code $response")
+                    val jsonArray = JSONArray(response.body?.string() ?: "")
+                    if (jsonArray.length() > 0) {
+                        for (i in 0 until jsonArray.length()) {
+                            val jsonObject = jsonArray.getJSONObject(i)
+                            try {
+                                val task = Utils.VideoUploadTaskInfo(
+                                    taskId = jsonObject.getString("taskId"),
+                                    title = jsonObject.getString("title"),
+                                    description = jsonObject.getString("description"),
+                                    datetime = jsonObject.getString("datetime"),
+                                    videoUrl = jsonObject.getString("videoUrl"),
+                                    coverUrl = jsonObject.getString("coverUrl")
+                                )
+                                uploadTaskList.add(task)
+                            } catch (e: Exception) {
+                                e.printStackTrace()
+                            }
+                        }
+                    }
+                }
+                // 鍦ㄨ姹傛垚鍔熷苟瑙f瀽瀹屼换鍔″垪琛ㄥ悗锛岃皟鐢ㄥ洖璋冨嚱鏁�
+                callback.onTasksFetched(uploadTaskList)
+            }
+        })
+    }
 
     suspend fun downloadCommonFileToExternalFilesDir(context: Context, url: String, filename: String, install: Boolean) {
         val tmpFile = File(context.getExternalFilesDir(null), filename)
@@ -220,18 +292,15 @@
                     override fun onFailure(call: Call, e: IOException) {
                         deferred.completeExceptionally(e) // 涓嬭浇澶辫触鏃舵爣璁颁负寮傚父
                     }
-
                     override fun onResponse(call: Call, response: Response) {
                         response.use {
                             if (!response.isSuccessful) {
                                 deferred.completeExceptionally(IOException("Unexpected code $response")) // 濡傛灉鍝嶅簲涓嶆垚鍔燂紝鏍囪涓哄紓甯�
                                 return
                             }
-
                             tmpFile.outputStream().use { outputStream ->
                                 outputStream.write(response.body?.bytes())
                             }
-
                             if (install) {
                                 installApk(context,tmpFile)
                             }
@@ -272,4 +341,24 @@
         return if (month in 1..12) months[month - 1] else "Invalid"
     }
 
+    // 鑾峰彇 key 鐨勪綅缃�
+    fun getSessionProfileValuePosition(key: String): Int {
+        val index = AppConfig.SESSION_PROFILE_TYPE.values.toList().indexOf(key)
+        return if (index == -1) 0 else index
+    }
+
+    fun getCurrentTimeString(): String {
+        val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()) // 鑷畾涔夋牸寮�
+        val currentDate = Date() // 鑾峰彇褰撳墠鏃堕棿
+        return formatter.format(currentDate) // 鏍煎紡鍖栦负瀛楃涓�
+    }
+
+    // 鏍规嵁浣嶇疆鑾峰彇 key
+    fun getSessionProfileValueByPosition(position: Int?): String? {
+        if (position==null){
+            return "Unknown"
+        }
+        return AppConfig.SESSION_PROFILE_TYPE.values.toList().getOrElse(position) { "Unknown" }
+    }
+
 }
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 5d101d8..1d24a6b 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -33,7 +33,7 @@
             android:text="@string/app_tab_upload"/>
 
         <Button
-            android:id="@+id/tabHelp"
+            android:id="@+id/tabSetting"
             android:layout_width="0dp"
             android:layout_height="48dp"
             android:layout_weight="1"
diff --git a/app/src/main/res/layout/activity_session_profile.xml b/app/src/main/res/layout/activity_session_profile.xml
new file mode 100644
index 0000000..9dcb938
--- /dev/null
+++ b/app/src/main/res/layout/activity_session_profile.xml
@@ -0,0 +1,102 @@
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:padding="6dp">
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+        <!-- 宸﹁竟鎸夐挳锛氳繑鍥� -->
+        <Button
+            android:id="@+id/btn_back"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="杩斿洖"
+            android:layout_alignParentStart="true" /> <!-- 闈犲乏瀵归綈 -->
+        <Button
+            android:id="@+id/btn_save"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="淇濆瓨閰嶇疆"
+            android:layout_alignParentEnd="true" /> <!-- 闈犲彸瀵归綈 -->
+
+    </RelativeLayout>
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+        <TextView
+            android:id="@+id/txt_session_id"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_centerInParent="true"
+            android:gravity="center"/>
+
+    </RelativeLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:weightSum="2"
+            android:padding="2dp">
+
+            <TextView
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:text="Name锛�" />
+
+            <EditText
+                android:id="@+id/edit_name"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1" />
+        </LinearLayout>
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:weightSum="2"
+            android:padding="2dp">
+
+            <TextView
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:text="Type锛�" />
+
+            <Spinner
+                android:id="@+id/spinner_type"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/switch_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:paddingTop="16dp" />
+
+        <ProgressBar
+            android:id="@+id/progressBar"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerInParent="true"
+            android:visibility="gone" />
+
+
+        <com.shsening.autouploadvideos.SessionProfileWebView
+            android:id="@+id/sessionProfileWebView"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:focusable="true"
+            android:focusableInTouchMode="true" />
+</LinearLayout>
+
diff --git a/app/src/main/res/layout/fragment_help.xml b/app/src/main/res/layout/fragment_help.xml
index bf57ba4..6972093 100644
--- a/app/src/main/res/layout/fragment_help.xml
+++ b/app/src/main/res/layout/fragment_help.xml
@@ -1,10 +1,44 @@
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <WebView
-        android:id="@+id/webView"
+    <LinearLayout
+        android:orientation="vertical"
         android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-</LinearLayout>
+        android:layout_height="wrap_content"
+        android:padding="16dp">
+
+        <TextView
+            android:id="@+id/androidIdText"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="18sp"
+            android:layout_marginBottom="16dp" />
+
+        <ImageView
+            android:id="@+id/imageView"
+            android:layout_width="300dp"
+            android:layout_height="300dp"
+            android:scaleType="centerCrop"
+            android:layout_marginBottom="16dp" />
+
+        <TextView
+            android:id="@+id/descriptionText"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="18sp"
+            android:gravity="center"
+            android:layout_marginBottom="16dp" />
+
+        <!-- 浣跨敤鍥哄畾楂樺害浠f浛 wrap_content -->
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+
+            <WebView
+                android:id="@+id/webView"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent" />
+        </FrameLayout>
+    </LinearLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_my.xml b/app/src/main/res/layout/fragment_my.xml
deleted file mode 100644
index 9372f52..0000000
--- a/app/src/main/res/layout/fragment_my.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:gravity="center"
-    android:padding="16dp">
-
-    <TextView
-        android:id="@+id/androidIdText"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:textSize="18sp"
-        android:layout_marginBottom="16dp"/>
-
-    <ImageView
-        android:id="@+id/imageView"
-        android:layout_width="300dp"
-        android:layout_height="300dp"
-        android:scaleType="centerCrop"
-        android:layout_marginBottom="16dp" />
-
-    <TextView
-        android:id="@+id/descriptionText"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:textSize="18sp"
-        android:gravity="center" />
-</LinearLayout>
diff --git a/app/src/main/res/layout/fragment_session_profile_list.xml b/app/src/main/res/layout/fragment_session_profile_list.xml
new file mode 100644
index 0000000..e3a7f37
--- /dev/null
+++ b/app/src/main/res/layout/fragment_session_profile_list.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+xmlns:android="http://schemas.android.com/apk/res/android"
+android:layout_width="match_parent"
+android:layout_height="match_parent"
+android:orientation="vertical">
+
+<RelativeLayout
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:padding="16dp">
+
+    <Button
+        android:id="@+id/btn_new"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentEnd="true"
+        android:layout_marginEnd="16dp"
+        android:text="鏂板缓" />
+</RelativeLayout>
+
+<ListView
+    android:id="@+id/list_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:divider="@android:color/darker_gray"
+    android:dividerHeight="1dp" />
+</LinearLayout>
diff --git a/app/src/main/res/layout/list_item_with_checkbox.xml b/app/src/main/res/layout/list_item_with_checkbox.xml
new file mode 100644
index 0000000..f5c78c0
--- /dev/null
+++ b/app/src/main/res/layout/list_item_with_checkbox.xml
@@ -0,0 +1,48 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:padding="8dp"
+    android:gravity="center_vertical">
+
+    <!-- 宸︿晶鐨� CheckBox -->
+    <CheckBox
+        android:id="@+id/itemCheckBox"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:checked="true"
+        android:layout_marginEnd="8dp" />
+
+    <LinearLayout
+        android:orientation="vertical"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:paddingEnd="8dp">
+
+        <TextView
+            android:id="@android:id/text1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="16sp"
+            android:textColor="@android:color/black" />
+
+        <TextView
+            android:id="@android:id/text2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="14sp"
+            android:textColor="@android:color/darker_gray" />
+    </LinearLayout>
+
+    <Button
+        android:id="@+id/deleteButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:focusable="false"
+        android:focusableInTouchMode="false"
+        android:clickable="true"
+        android:text="涓婁紶"
+        android:textColor="@android:color/holo_blue_light"
+        android:background="?android:attr/selectableItemBackground" />
+</LinearLayout>
diff --git a/app/src/main/res/layout/list_item_with_delete.xml b/app/src/main/res/layout/list_item_with_delete.xml
new file mode 100644
index 0000000..6a89125
--- /dev/null
+++ b/app/src/main/res/layout/list_item_with_delete.xml
@@ -0,0 +1,40 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:padding="8dp"
+    android:gravity="center_vertical">
+
+    <LinearLayout
+        android:orientation="vertical"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:paddingEnd="8dp">
+
+        <TextView
+            android:id="@android:id/text1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="16sp"
+            android:textColor="@android:color/black" />
+
+        <TextView
+            android:id="@android:id/text2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="14sp"
+            android:textColor="@android:color/darker_gray" />
+    </LinearLayout>
+
+    <Button
+        android:id="@+id/deleteButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:focusable="false"
+        android:focusableInTouchMode="false"
+        android:clickable="true"
+        android:text="鍒犻櫎"
+        android:textColor="@android:color/holo_blue_light"
+        android:background="?android:attr/selectableItemBackground" />
+</LinearLayout>
diff --git a/app/src/main/res/layout/upload_list.xml b/app/src/main/res/layout/upload_list.xml
new file mode 100644
index 0000000..e73d09d
--- /dev/null
+++ b/app/src/main/res/layout/upload_list.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+xmlns:android="http://schemas.android.com/apk/res/android"
+android:layout_width="match_parent"
+android:layout_height="match_parent"
+android:orientation="vertical">
+    <Button
+        android:id="@+id/btn_all_task"
+        android:layout_width="match_parent"
+        android:layout_height="48dp"
+        android:background="@color/teal_200"
+        android:text="涓�閿笂浼犳墍鏈変换鍔�" />
+
+
+<ListView
+    android:id="@+id/upload_list_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:divider="@android:color/darker_gray"
+    android:dividerHeight="1dp" />
+</LinearLayout>
diff --git a/app/src/main/res/layout/upload_session.xml b/app/src/main/res/layout/upload_session.xml
new file mode 100644
index 0000000..dc8d181
--- /dev/null
+++ b/app/src/main/res/layout/upload_session.xml
@@ -0,0 +1,41 @@
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:padding="6dp">
+
+
+        <RelativeLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_vertical">
+
+                <Button
+                    android:id="@+id/btn_upload_back"
+                    android:layout_width="wrap_content"
+                    android:layout_height="48dp"
+                    android:layout_alignParentStart="true"
+                    android:gravity="center"
+                    android:text="杩斿洖" />
+
+                <TextView
+                    android:id="@+id/uploadSessionText"
+                    android:layout_width="250dp"
+                    android:layout_height="48dp"
+                    android:layout_alignParentRight="true"
+                    android:background="@color/teal_200"
+                    android:gravity="center" />
+
+        </RelativeLayout>
+
+        <com.shsening.autouploadvideos.SessionProfileWebView
+            android:id="@+id/uploadSessionWebView"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:focusable="true"
+            android:focusableInTouchMode="true" />
+</LinearLayout>
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index dcbaff1..e4715e0 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -2,8 +2,8 @@
     <string name="app_name">Video Upload</string>
     <string name="hello_blank_fragment">Hello blank fragment</string>
     <string name="app_tab_upload">涓婁紶瑙嗛</string>
-    <string name="app_tab_description">浣跨敤璇存槑</string>
-    <string name="app_tab_my">鎴戠殑</string>
+    <string name="app_tab_description">妯℃澘璁剧疆</string>
+    <string name="app_tab_my">浣跨敤璇存槑</string>
 
     <string name="msg_douyin">鎶栭煶</string>
     <string name="msg_kuaishou">蹇墜</string>
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 9b49ed9..53a32c2 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -12,7 +12,8 @@
 appcompat="1.6.0"
 constraintlayout="2.1.4"
 material = "1.12.0"
-
+parcelize="2.1.0"
+firebaseStorageKtx = "21.0.1"
 [libraries]
 androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
 junit = { group = "junit", name = "junit", version.ref = "junit" }
@@ -32,9 +33,8 @@
 appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
 constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
 material = { group = "com.google.android.material", name = "material", version.ref = "material" }
-
+firebase-storage-ktx = { group = "com.google.firebase", name = "firebase-storage-ktx", version.ref = "firebaseStorageKtx" }
 
 [plugins]
 android-application = { id = "com.android.application", version.ref = "agp" }
 jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
-

--
Gitblit v1.9.1