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