From e40041bde73cd7209528187e2b2b9853bcc781d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E9=B2=AB=E9=9B=AA=E7=8B=90?= <139336664+ArcticFoxPro@users.noreply.github.com> Date: Fri, 6 Sep 2024 18:06:08 +0800 Subject: [PATCH 01/23] =?UTF-8?q?refactor(main):=20=E5=AE=9E=E7=8E=B0ViewP?= =?UTF-8?q?ager2=E4=BB=A5=E4=BC=98=E5=8C=96RecyclerView=E5=B8=83=E5=B1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 通过改用ViewPager2,重构`MainActivity`以支持更流畅的布局切换。此更改包括将`RecyclerView`替换为`ViewPager2`,并调整相关适配器以支持新的分页视图结构。同时,更新应用版本号至1.3.8,并引入`viewpager2`和`fragment-ktx`库以支持新功能。 这个提交有问题,versionListStaggeredGridLayout()外部调用闪退报错未初始化 --- app/build.gradle.kts | 4 +- .../xiaoniu/qqversionlist/ui/MainActivity.kt | 128 +++++++++++++----- app/src/main/res/layout/activity_main.xml | 8 +- .../main/res/layout/recycle_qq_version.xml | 14 ++ 4 files changed, 111 insertions(+), 43 deletions(-) create mode 100644 app/src/main/res/layout/recycle_qq_version.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6e63494..d9c9cba 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -46,7 +46,7 @@ android { minSdk = 24 targetSdk = 35 versionCode = gitCommitCount - versionName = "1.3.7-$gitCommitHash" + versionName = "1.3.8-$gitCommitHash" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" externalNativeBuild { cmake { @@ -109,4 +109,6 @@ dependencies { implementation("com.airbnb.android:paris:2.0.2") implementation("org.apache.maven:maven-artifact:3.9.9") implementation("androidx.recyclerview:recyclerview:1.3.2") + implementation("androidx.viewpager2:viewpager2:1.1.0") + implementation("androidx.fragment:fragment-ktx:1.8.3") } diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/ui/MainActivity.kt b/app/src/main/java/com/xiaoniu/qqversionlist/ui/MainActivity.kt index 0fa484e..34c7481 100644 --- a/app/src/main/java/com/xiaoniu/qqversionlist/ui/MainActivity.kt +++ b/app/src/main/java/com/xiaoniu/qqversionlist/ui/MainActivity.kt @@ -51,11 +51,15 @@ import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.updateLayoutParams import androidx.core.view.updatePadding +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentActivity import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.ConcatAdapter import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.StaggeredGridLayoutManager +import androidx.viewpager2.adapter.FragmentStateAdapter +import androidx.viewpager2.widget.ViewPager2 import com.airbnb.paris.extensions.style import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog @@ -82,6 +86,7 @@ import com.xiaoniu.qqversionlist.databinding.DialogSettingBinding import com.xiaoniu.qqversionlist.databinding.DialogShiplyBackBinding import com.xiaoniu.qqversionlist.databinding.DialogShiplyBinding import com.xiaoniu.qqversionlist.databinding.DialogSuffixDefineBinding +import com.xiaoniu.qqversionlist.databinding.RecycleQqVersionBinding import com.xiaoniu.qqversionlist.databinding.SuccessButtonBinding import com.xiaoniu.qqversionlist.databinding.UserAgreementBinding import com.xiaoniu.qqversionlist.util.ClipboardUtil.copyText @@ -109,9 +114,11 @@ import java.util.zip.GZIPInputStream class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding - private lateinit var versionAdapter: VersionAdapter - private lateinit var localQQAdapter: LocalQQAdapter + lateinit var versionAdapter: VersionAdapter + lateinit var localQQAdapter: LocalQQAdapter private lateinit var qqVersion: List + private lateinit var recycleViewFragmentAdapter: RecycleViewFragmentAdapter + private lateinit var rvPagerAdapter: RecycleViewPagerAdapter override fun onCreate(savedInstanceState: Bundle?) { enableEdgeToEdge() @@ -146,44 +153,34 @@ class MainActivity : AppCompatActivity() { versionAdapter = VersionAdapter() localQQAdapter = LocalQQAdapter() - versionListStaggeredGridLayout() + binding.rvPager.adapter = RecycleViewPagerAdapter(this) + rvPagerAdapter = binding.rvPager.adapter as RecycleViewPagerAdapter + recycleViewFragmentAdapter = RecycleViewFragmentAdapter() initButtons() + binding.rvPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { + override fun onPageSelected(position: Int) { + super.onPageSelected(position) + recycleViewFragmentAdapter = + rvPagerAdapter.getFragementAtPosition(position) as RecycleViewFragmentAdapter + } + }) + if (!BuildConfig.VERSION_NAME.endsWith("Release")) binding.materialToolbar.setNavigationIcon( R.drawable.git_commit_line ) + + } override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) - versionListStaggeredGridLayout() + recycleViewFragmentAdapter.versionListStaggeredGridLayout() } override fun onMultiWindowModeChanged(isInMultiWindowMode: Boolean, newConfig: Configuration) { super.onMultiWindowModeChanged(isInMultiWindowMode, newConfig) - versionListStaggeredGridLayout() - } - - private fun versionListStaggeredGridLayout() { - binding.rvContent.apply { - val concatenated = ConcatAdapter(localQQAdapter, versionAdapter) - adapter = concatenated - val screenWidthDp = (Resources.getSystem().displayMetrics.widthPixels).pxToDp - val screenHeightDp = (Resources.getSystem().displayMetrics.heightPixels).pxToDp - layoutManager = if (screenHeightDp >= 600) { - when { - screenWidthDp in 600..840 -> StaggeredGridLayoutManager( - 2, StaggeredGridLayoutManager.VERTICAL - ) - - screenWidthDp > 840 -> StaggeredGridLayoutManager( - 3, StaggeredGridLayoutManager.VERTICAL - ) - - else -> LinearLayoutManager(this@MainActivity) - } - } else LinearLayoutManager(this@MainActivity) - } + recycleViewFragmentAdapter.versionListStaggeredGridLayout() } private fun showUADialog(agreed: Boolean, UATarget: Int) { @@ -251,15 +248,6 @@ class MainActivity : AppCompatActivity() { hideAnimationBehavior = LinearProgressIndicator.HIDE_ESCAPE } - binding.rvContent.addOnScrollListener(object : RecyclerView.OnScrollListener() { - override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { - super.onScrolled(recyclerView, dx, dy) - if (dy > 0) binding.btnGuess.shrink() - else if (dy < 0) binding.btnGuess.extend() - } - }) - - binding.bottomAppBar.setOnMenuItemClickListener { menuItem -> //底部左下角按钮动作 when (menuItem.itemId) { @@ -1618,6 +1606,74 @@ class MainActivity : AppCompatActivity() { } } + class RecycleViewPagerAdapter(private val context: Context) : + FragmentStateAdapter(context as FragmentActivity) { + override fun getItemCount(): Int = 1 + + override fun createFragment(position: Int): Fragment { + return RecycleViewFragmentAdapter() + } + + fun getFragementAtPosition(position: Int): RecycleViewFragmentAdapter? { + return when (position) { + 0 -> RecycleViewFragmentAdapter() + else -> null + } + } + } + + class RecycleViewFragmentAdapter : Fragment() { + private lateinit var fragmentBinding: RecycleQqVersionBinding + private lateinit var thisActivity: MainActivity + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + fragmentBinding = RecycleQqVersionBinding.inflate(inflater, container, false) + val view = fragmentBinding.root + thisActivity = requireActivity() as MainActivity + return view + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + versionListStaggeredGridLayout() + fragmentBinding.rvContent.addOnScrollListener(object : RecyclerView.OnScrollListener() { + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + super.onScrolled(recyclerView, dx, dy) + handleScroll(dy) + } + }) + } + + fun versionListStaggeredGridLayout() { + fragmentBinding.rvContent.apply { + val concatenated = + ConcatAdapter(thisActivity.localQQAdapter, thisActivity.versionAdapter) + adapter = concatenated + val screenWidthDp = (Resources.getSystem().displayMetrics.widthPixels).pxToDp + val screenHeightDp = (Resources.getSystem().displayMetrics.heightPixels).pxToDp + layoutManager = if (screenHeightDp >= 600) { + when { + screenWidthDp in 600..840 -> StaggeredGridLayoutManager( + 2, StaggeredGridLayoutManager.VERTICAL + ) + + screenWidthDp > 840 -> StaggeredGridLayoutManager( + 3, StaggeredGridLayoutManager.VERTICAL + ) + + else -> LinearLayoutManager(thisActivity) + } + } else LinearLayoutManager(thisActivity) + } + } + + private fun handleScroll(dy: Int) { + if (dy > 0) thisActivity.binding.btnGuess.shrink() + else if (dy < 0) thisActivity.binding.btnGuess.extend() + } + } + class ShiplyAdvancedConfigSheet : BottomSheetDialogFragment() { private lateinit var shiplyAdvancedConfigSheetBinding: BottomsheetShiplyAdvancedConfigBinding diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 474ba57..c101e1a 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -24,16 +24,12 @@ android:fitsSystemWindows="true" tools:context=".ui.MainActivity"> - diff --git a/app/src/main/res/layout/recycle_qq_version.xml b/app/src/main/res/layout/recycle_qq_version.xml new file mode 100644 index 0000000..bbd34f3 --- /dev/null +++ b/app/src/main/res/layout/recycle_qq_version.xml @@ -0,0 +1,14 @@ + + \ No newline at end of file From 3d8b35ed1364a231a753892e8548dc25af232904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E9=B2=AB=E9=9B=AA=E7=8B=90?= <139336664+ArcticFoxPro@users.noreply.github.com> Date: Fri, 6 Sep 2024 21:25:39 +0800 Subject: [PATCH 02/23] =?UTF-8?q?=E5=90=8C=E4=B8=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/xiaoniu/qqversionlist/ui/MainActivity.kt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/ui/MainActivity.kt b/app/src/main/java/com/xiaoniu/qqversionlist/ui/MainActivity.kt index 34c7481..0c84645 100644 --- a/app/src/main/java/com/xiaoniu/qqversionlist/ui/MainActivity.kt +++ b/app/src/main/java/com/xiaoniu/qqversionlist/ui/MainActivity.kt @@ -53,6 +53,8 @@ import androidx.core.view.updateLayoutParams import androidx.core.view.updatePadding import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity +import androidx.fragment.app.viewModels +import androidx.lifecycle.ViewModel import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.ConcatAdapter import androidx.recyclerview.widget.LinearLayoutManager @@ -1623,12 +1625,14 @@ class MainActivity : AppCompatActivity() { } class RecycleViewFragmentAdapter : Fragment() { - private lateinit var fragmentBinding: RecycleQqVersionBinding + private var _fragmentBinding: RecycleQqVersionBinding? = null + private val fragmentBinding get() = _fragmentBinding!! private lateinit var thisActivity: MainActivity + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { - fragmentBinding = RecycleQqVersionBinding.inflate(inflater, container, false) + _fragmentBinding = RecycleQqVersionBinding.inflate(inflater, container, false) val view = fragmentBinding.root thisActivity = requireActivity() as MainActivity return view @@ -1672,6 +1676,11 @@ class MainActivity : AppCompatActivity() { if (dy > 0) thisActivity.binding.btnGuess.shrink() else if (dy < 0) thisActivity.binding.btnGuess.extend() } + + override fun onDestroyView() { + super.onDestroyView() + _fragmentBinding = null + } } class ShiplyAdvancedConfigSheet : BottomSheetDialogFragment() { From 8f7528da26b5a9126668bc1bfd6dee0a7c537a1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E9=B2=AB=E9=9B=AA=E7=8B=90?= <139336664+ArcticFoxPro@users.noreply.github.com> Date: Sun, 8 Sep 2024 10:27:47 +0800 Subject: [PATCH 03/23] =?UTF-8?q?refactor(app):=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E5=9B=BE=E6=A0=87=E5=B9=B6=E4=BC=98=E5=8C=96=E5=B8=83=E5=B1=80?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 替换了多个XML图标文件,统一了图标风格。 - 从`item_version.xml`和`item_version_detail.xml`中移除了不必要的ImageViews。 - 在`MainActivity.kt`中进行了代码清理,提高了代码可读性。 - 修正了`VersionAdapter`的实例化方式,避免了潜在的内存泄漏问题。 -从`item_version.xml`和`item_version_detail.xml`中移除了不必要的ImageViews,简化了布局结构。 - 在`MainActivity.kt`中,将`RecycleViewPagerAdapter`和`RecycleViewFragmentAdapter`的实现调整为`QQVersionListFragmentAdapter`和`VersionListPagerAdapter`,提高了组件的专用性和清晰度。 - 通过移除`RecycleViewPagerAdapter`和`RecycleViewFragmentAdapter`中冗余的`getFragementAtPosition`方法,优化了代码结构。- 在`ShiplyAdvancedConfigSheet`中移除了复杂的布局和事件处理代码,减少了潜在的内存泄漏风险。 --- README.md | 2 +- .../qqversionlist/TipTimeApplication.kt | 1 + .../qqversionlist/data/QQVersionBean.kt | 3 +- .../xiaoniu/qqversionlist/ui/MainActivity.kt | 211 ++---------------- .../ui/QQVersionListFragmentAdapter.kt | 73 ++++++ .../ui/ShiplyAdvancedConfigSheetFragment.kt | 114 ++++++++++ .../qqversionlist/ui/VersionAdapter.kt | 11 +- .../ui/VersionListPagerAdapter.kt | 22 ++ app/src/main/res/drawable/alert_line.xml | 21 +- app/src/main/res/drawable/apps_line.xml | 15 ++ .../main/res/drawable/arrow_down_s_line.xml | 26 +++ .../main/res/drawable/arrow_right_s_line.xml | 15 ++ app/src/main/res/drawable/arrow_up_s_line.xml | 26 +++ app/src/main/res/drawable/braces_line.xml | 15 ++ app/src/main/res/drawable/check_circle.xml | 15 ++ app/src/main/res/drawable/clipboard_line.xml | 15 ++ app/src/main/res/drawable/download_line.xml | 15 ++ .../main/res/drawable/error_warning_fill.xml | 15 ++ app/src/main/res/drawable/file_copy_line.xml | 15 ++ app/src/main/res/drawable/file_text_line.xml | 15 ++ app/src/main/res/drawable/flask_line.xml | 15 ++ app/src/main/res/drawable/git_commit_line.xml | 15 ++ app/src/main/res/drawable/ic_down.xml | 11 - app/src/main/res/drawable/ic_up.xml | 11 - .../main/res/drawable/information_line.xml | 15 ++ app/src/main/res/drawable/palette_line.xml | 15 ++ app/src/main/res/drawable/phone_find_line.xml | 15 ++ .../res/drawable/qqnt_logo_unofficial.xml | 45 ++++ app/src/main/res/drawable/question_line.xml | 15 ++ app/src/main/res/drawable/refresh_line.xml | 15 ++ app/src/main/res/drawable/save_line.xml | 15 ++ app/src/main/res/drawable/scan_line.xml | 15 ++ app/src/main/res/drawable/search_line.xml | 15 ++ .../search_shortcut_icon_foreground.xml | 15 ++ app/src/main/res/drawable/settings_line.xml | 15 ++ app/src/main/res/drawable/share_line.xml | 15 ++ .../main/res/drawable/skip_forward_line.xml | 15 ++ app/src/main/res/drawable/sparkling_line.xml | 15 ++ app/src/main/res/drawable/stop_fill.xml | 15 ++ app/src/main/res/drawable/stop_line.xml | 15 ++ app/src/main/res/layout/item_version.xml | 17 +- .../main/res/layout/item_version_detail.xml | 17 +- app/src/main/res/values-ar-rSA/strings.xml | 1 + app/src/main/res/values-en-rUS/strings.xml | 1 + app/src/main/res/values-es-rES/strings.xml | 1 + app/src/main/res/values-fr-rFR/strings.xml | 1 + app/src/main/res/values-ja-rJP/strings.xml | 1 + app/src/main/res/values-ko-rKR/strings.xml | 1 + app/src/main/res/values-ru-rRU/strings.xml | 1 + app/src/main/res/values-zh-rCN/strings.xml | 1 + app/src/main/res/values-zh-rHK/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 52 files changed, 784 insertions(+), 227 deletions(-) create mode 100644 app/src/main/java/com/xiaoniu/qqversionlist/ui/QQVersionListFragmentAdapter.kt create mode 100644 app/src/main/java/com/xiaoniu/qqversionlist/ui/ShiplyAdvancedConfigSheetFragment.kt create mode 100644 app/src/main/java/com/xiaoniu/qqversionlist/ui/VersionListPagerAdapter.kt create mode 100644 app/src/main/res/drawable/arrow_down_s_line.xml create mode 100644 app/src/main/res/drawable/arrow_up_s_line.xml delete mode 100644 app/src/main/res/drawable/ic_down.xml delete mode 100644 app/src/main/res/drawable/ic_up.xml create mode 100644 app/src/main/res/drawable/qqnt_logo_unofficial.xml diff --git a/README.md b/README.md index ddafcc7..a247206 100644 --- a/README.md +++ b/README.md @@ -194,7 +194,7 @@ QQ 版本列表实用工具不能实现“检测到新版本自动提醒您” > QQ 版本列表实用工具始终坚守法律底线,秉持尊重与保护所有用户及第三方合法权益的原则。我们深切认识到任何可能存在的权益侵犯行为都会对权益方造成潜在影响,对此,我们表示由衷歉意,并承诺,一旦接到权益方的权益受到侵犯的通知,我们将立即依法启动核查程序,并在确认侵权事实后,迅速采取有效措施,以最大程度地消除不良影响,恢复并保障权益方的合法权益。敬请相关权益方在发现 QQ 版本列表实用工具存在任何侵权内容时,及时与我们取得联系,我们将竭诚为权益方提供必要的协助与支持。 > [!NOTE] -> “腾讯”“QQ”“腾讯 QQ”“微信”“WeChat”“微信输入法”“WeType”是深圳市腾讯计算机系统有限公司和/或其关联公司的商标。本应用对“腾讯”“QQ”“腾讯 QQ”“微信”“WeChat”“微信输入法”“WeType”的使用旨在注明和指向对应主体,并非表示对“腾讯”“QQ”“腾讯 QQ”“微信”“WeChat”“微信输入法”“WeType”商标的注册和拥有。 +> “腾讯”“QQ”“腾讯 QQ”“微信”“WeChat”“微信输入法”“WeType”是深圳市腾讯计算机系统有限公司和/或其关联公司的商标。本项目对“腾讯”“QQ”“腾讯 QQ”“微信”“WeChat”“微信输入法”“WeType”的使用旨在注明和指向对应主体,并非表示对“腾讯”“QQ”“腾讯 QQ”“微信”“WeChat”“微信输入法”“WeType”商标的注册和拥有。 > [!NOTE] > Android™ 是 Google LLC 的商标。 diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/TipTimeApplication.kt b/app/src/main/java/com/xiaoniu/qqversionlist/TipTimeApplication.kt index f69ecc6..2307487 100644 --- a/app/src/main/java/com/xiaoniu/qqversionlist/TipTimeApplication.kt +++ b/app/src/main/java/com/xiaoniu/qqversionlist/TipTimeApplication.kt @@ -29,6 +29,7 @@ class TipTimeApplication : Application() { const val SHIPLY_DEFAULT_SDK_VERSION = "1.3.36-RC01" const val EARLIEST_ACCESSIBILITY_VERSION = false + const val EARLIEST_QQNT_FRAMEWORK_VERSION_STABLE = "8.9.63" } override fun onCreate() { diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/data/QQVersionBean.kt b/app/src/main/java/com/xiaoniu/qqversionlist/data/QQVersionBean.kt index 8199862..ff8b4b3 100644 --- a/app/src/main/java/com/xiaoniu/qqversionlist/data/QQVersionBean.kt +++ b/app/src/main/java/com/xiaoniu/qqversionlist/data/QQVersionBean.kt @@ -33,5 +33,6 @@ data class QQVersionBean( var jsonString: String = "", var displayType: Int = 0, // 0为收起 var displayInstall: Boolean = false, // false 为不展示 - var isAccessibility: Boolean = false + var isAccessibility: Boolean = false, + var isQQNTFramework: Boolean = false ) diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/ui/MainActivity.kt b/app/src/main/java/com/xiaoniu/qqversionlist/ui/MainActivity.kt index 0c84645..0c8eff4 100644 --- a/app/src/main/java/com/xiaoniu/qqversionlist/ui/MainActivity.kt +++ b/app/src/main/java/com/xiaoniu/qqversionlist/ui/MainActivity.kt @@ -36,12 +36,10 @@ import android.text.SpannableString import android.text.TextWatcher import android.text.style.URLSpan import android.util.Base64 -import android.view.LayoutInflater import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.view.inputmethod.InputMethodManager -import android.widget.Toast import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatActivity import androidx.constraintlayout.widget.ConstraintSet @@ -51,21 +49,10 @@ import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.updateLayoutParams import androidx.core.view.updatePadding -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentActivity -import androidx.fragment.app.viewModels -import androidx.lifecycle.ViewModel import androidx.lifecycle.lifecycleScope -import androidx.recyclerview.widget.ConcatAdapter import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import androidx.recyclerview.widget.StaggeredGridLayoutManager -import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.widget.ViewPager2 import com.airbnb.paris.extensions.style -import com.google.android.material.bottomsheet.BottomSheetBehavior -import com.google.android.material.bottomsheet.BottomSheetDialog -import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.button.MaterialButton import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.progressindicator.CircularProgressIndicatorSpec @@ -75,11 +62,11 @@ import com.google.gson.GsonBuilder import com.google.gson.JsonElement import com.xiaoniu.qqversionlist.BuildConfig import com.xiaoniu.qqversionlist.R +import com.xiaoniu.qqversionlist.TipTimeApplication.Companion.EARLIEST_QQNT_FRAMEWORK_VERSION_STABLE import com.xiaoniu.qqversionlist.TipTimeApplication.Companion.SHIPLY_DEFAULT_APPID import com.xiaoniu.qqversionlist.TipTimeApplication.Companion.SHIPLY_DEFAULT_SDK_VERSION import com.xiaoniu.qqversionlist.data.QQVersionBean import com.xiaoniu.qqversionlist.databinding.ActivityMainBinding -import com.xiaoniu.qqversionlist.databinding.BottomsheetShiplyAdvancedConfigBinding import com.xiaoniu.qqversionlist.databinding.DialogAboutBinding import com.xiaoniu.qqversionlist.databinding.DialogGuessBinding import com.xiaoniu.qqversionlist.databinding.DialogLoadingBinding @@ -88,7 +75,6 @@ import com.xiaoniu.qqversionlist.databinding.DialogSettingBinding import com.xiaoniu.qqversionlist.databinding.DialogShiplyBackBinding import com.xiaoniu.qqversionlist.databinding.DialogShiplyBinding import com.xiaoniu.qqversionlist.databinding.DialogSuffixDefineBinding -import com.xiaoniu.qqversionlist.databinding.RecycleQqVersionBinding import com.xiaoniu.qqversionlist.databinding.SuccessButtonBinding import com.xiaoniu.qqversionlist.databinding.UserAgreementBinding import com.xiaoniu.qqversionlist.util.ClipboardUtil.copyText @@ -98,7 +84,6 @@ import com.xiaoniu.qqversionlist.util.InfoUtil.showToast import com.xiaoniu.qqversionlist.util.ShiplyUtil import com.xiaoniu.qqversionlist.util.StringUtil.getAllAPKUrl import com.xiaoniu.qqversionlist.util.StringUtil.toPrettyFormat -import com.xiaoniu.qqversionlist.util.pxToDp import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -106,6 +91,7 @@ import kotlinx.coroutines.withContext import kotlinx.serialization.json.Json import okhttp3.OkHttpClient import okhttp3.Request +import org.apache.maven.artifact.versioning.DefaultArtifactVersion import java.io.BufferedReader import java.io.ByteArrayInputStream import java.io.InputStreamReader @@ -115,12 +101,12 @@ import java.util.zip.GZIPInputStream class MainActivity : AppCompatActivity() { - private lateinit var binding: ActivityMainBinding + lateinit var binding: ActivityMainBinding lateinit var versionAdapter: VersionAdapter lateinit var localQQAdapter: LocalQQAdapter private lateinit var qqVersion: List - private lateinit var recycleViewFragmentAdapter: RecycleViewFragmentAdapter - private lateinit var rvPagerAdapter: RecycleViewPagerAdapter + private lateinit var recycleViewFragmentAdapter: QQVersionListFragmentAdapter + private lateinit var rvPagerAdapter: VersionListPagerAdapter override fun onCreate(savedInstanceState: Bundle?) { enableEdgeToEdge() @@ -155,16 +141,16 @@ class MainActivity : AppCompatActivity() { versionAdapter = VersionAdapter() localQQAdapter = LocalQQAdapter() - binding.rvPager.adapter = RecycleViewPagerAdapter(this) - rvPagerAdapter = binding.rvPager.adapter as RecycleViewPagerAdapter - recycleViewFragmentAdapter = RecycleViewFragmentAdapter() + binding.rvPager.adapter = VersionListPagerAdapter(this) + rvPagerAdapter = binding.rvPager.adapter as VersionListPagerAdapter + recycleViewFragmentAdapter = QQVersionListFragmentAdapter() initButtons() binding.rvPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { override fun onPageSelected(position: Int) { super.onPageSelected(position) recycleViewFragmentAdapter = - rvPagerAdapter.getFragementAtPosition(position) as RecycleViewFragmentAdapter + rvPagerAdapter.getFragementAtPosition(position) as QQVersionListFragmentAdapter } }) @@ -688,9 +674,9 @@ class MainActivity : AppCompatActivity() { } shiplyAdvancedConfigurationsClick.setOnClickListener { - ShiplyAdvancedConfigSheet().apply { + ShiplyAdvancedConfigSheetFragment().apply { isCancelable = false - show(supportFragmentManager, ShiplyAdvancedConfigSheet.TAG) + show(supportFragmentManager, ShiplyAdvancedConfigSheetFragment.TAG) } } @@ -1084,11 +1070,15 @@ class MainActivity : AppCompatActivity() { "QQVersionInstall", "" ) == this.versionNumber) this.isAccessibility = false - // 无障碍标记 /*DefaultArtifactVersion(this.versionNumber) >= DefaultArtifactVersion( EARLIEST_ACCESSIBILITY_VERSION )*/ + + this.isQQNTFramework = + DefaultArtifactVersion(this.versionNumber) >= DefaultArtifactVersion( + EARLIEST_QQNT_FRAMEWORK_VERSION_STABLE + ) } } if (DataStoreUtil.getBoolean( @@ -1608,175 +1598,6 @@ class MainActivity : AppCompatActivity() { } } - class RecycleViewPagerAdapter(private val context: Context) : - FragmentStateAdapter(context as FragmentActivity) { - override fun getItemCount(): Int = 1 - - override fun createFragment(position: Int): Fragment { - return RecycleViewFragmentAdapter() - } - - fun getFragementAtPosition(position: Int): RecycleViewFragmentAdapter? { - return when (position) { - 0 -> RecycleViewFragmentAdapter() - else -> null - } - } - } - - class RecycleViewFragmentAdapter : Fragment() { - private var _fragmentBinding: RecycleQqVersionBinding? = null - private val fragmentBinding get() = _fragmentBinding!! - private lateinit var thisActivity: MainActivity - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View { - _fragmentBinding = RecycleQqVersionBinding.inflate(inflater, container, false) - val view = fragmentBinding.root - thisActivity = requireActivity() as MainActivity - return view - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - versionListStaggeredGridLayout() - fragmentBinding.rvContent.addOnScrollListener(object : RecyclerView.OnScrollListener() { - override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { - super.onScrolled(recyclerView, dx, dy) - handleScroll(dy) - } - }) - } - - fun versionListStaggeredGridLayout() { - fragmentBinding.rvContent.apply { - val concatenated = - ConcatAdapter(thisActivity.localQQAdapter, thisActivity.versionAdapter) - adapter = concatenated - val screenWidthDp = (Resources.getSystem().displayMetrics.widthPixels).pxToDp - val screenHeightDp = (Resources.getSystem().displayMetrics.heightPixels).pxToDp - layoutManager = if (screenHeightDp >= 600) { - when { - screenWidthDp in 600..840 -> StaggeredGridLayoutManager( - 2, StaggeredGridLayoutManager.VERTICAL - ) - - screenWidthDp > 840 -> StaggeredGridLayoutManager( - 3, StaggeredGridLayoutManager.VERTICAL - ) - - else -> LinearLayoutManager(thisActivity) - } - } else LinearLayoutManager(thisActivity) - } - } - - private fun handleScroll(dy: Int) { - if (dy > 0) thisActivity.binding.btnGuess.shrink() - else if (dy < 0) thisActivity.binding.btnGuess.extend() - } - - override fun onDestroyView() { - super.onDestroyView() - _fragmentBinding = null - } - } - - class ShiplyAdvancedConfigSheet : BottomSheetDialogFragment() { - private lateinit var shiplyAdvancedConfigSheetBinding: BottomsheetShiplyAdvancedConfigBinding - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View = inflater.inflate(R.layout.bottomsheet_shiply_advanced_config, container, false) - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - dialog?.setCanceledOnTouchOutside(false) - shiplyAdvancedConfigSheetBinding = BottomsheetShiplyAdvancedConfigBinding.bind(view) - val shiplyAdvancedConfigSheetBehavior = (this.dialog as BottomSheetDialog).behavior - shiplyAdvancedConfigSheetBehavior.isDraggable = false - this@ShiplyAdvancedConfigSheet.isCancelable = true - shiplyAdvancedConfigSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED - this@ShiplyAdvancedConfigSheet.isCancelable = false - shiplyAdvancedConfigSheetBinding.apply { - shiplyAppid.helperText = - getString(R.string.shiplyGeneralOptionalHelpText) + SHIPLY_DEFAULT_APPID - shiplyModel.helperText = - getString(R.string.shiplyGeneralOptionalHelpText) + Build.MODEL.toString() - shiplyOsVersion.helperText = - getString(R.string.shiplyGeneralOptionalHelpText) + SDK_INT.toString() - shiplySdkVersion.helperText = - getString(R.string.shiplyGeneralOptionalHelpText) + SHIPLY_DEFAULT_SDK_VERSION - shiplyLanguage.helperText = - getString(R.string.shiplyGeneralOptionalHelpText) + Locale.getDefault().language.toString() - - DataStoreUtil.apply { - shiplyAppid.editText?.setText(getString("shiplyAppid", "")) - shiplyOsVersion.editText?.setText( - getString("shiplyOsVersion", "") - ) - shiplyModel.editText?.setText(getString("shiplyModel", "")) - shiplySdkVersion.editText?.setText( - getString("shiplySdkVersion", "") - ) - shiplyLanguage.editText?.setText( - getString("shiplyLanguage", "") - ) - - btnShiplyConfigSave.setOnClickListener { - shiplyAppid.clearFocus() - shiplyOsVersion.clearFocus() - shiplyModel.clearFocus() - shiplySdkVersion.clearFocus() - shiplyLanguage.clearFocus() - val imm = - requireContext().getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager - imm.hideSoftInputFromWindow(shiplyLanguage.windowToken, 0) - putStringAsync( - "shiplyAppid", shiplyAppid.editText?.text.toString() - ) - putStringAsync( - "shiplyOsVersion", shiplyOsVersion.editText?.text.toString() - ) - putStringAsync( - "shiplyModel", shiplyModel.editText?.text.toString() - ) - putStringAsync( - "shiplySdkVersion", shiplySdkVersion.editText?.text.toString() - ) - putStringAsync( - "shiplyLanguage", shiplyLanguage.editText?.text.toString() - ) - Toast.makeText(requireContext(), R.string.saved, Toast.LENGTH_SHORT).show() - this@ShiplyAdvancedConfigSheet.isCancelable = true - shiplyAdvancedConfigSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN - } - } - - btnShiplyConfigBack.setOnClickListener { - val imm = - requireContext().getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager - imm.hideSoftInputFromWindow(shiplyLanguage.windowToken, 0) - this@ShiplyAdvancedConfigSheet.isCancelable = true - shiplyAdvancedConfigSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN - } - - dragHandleView.setOnClickListener { - val imm = - requireContext().getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager - imm.hideSoftInputFromWindow(shiplyLanguage.windowToken, 0) - this@ShiplyAdvancedConfigSheet.isCancelable = true - shiplyAdvancedConfigSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN - } - } - } - - companion object { - const val TAG = "ShiplyAdvancedConfigSheet" - } - } - companion object { @SuppressLint("StaticFieldLeak") diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/ui/QQVersionListFragmentAdapter.kt b/app/src/main/java/com/xiaoniu/qqversionlist/ui/QQVersionListFragmentAdapter.kt new file mode 100644 index 0000000..7be1d65 --- /dev/null +++ b/app/src/main/java/com/xiaoniu/qqversionlist/ui/QQVersionListFragmentAdapter.kt @@ -0,0 +1,73 @@ +package com.xiaoniu.qqversionlist.ui + +import android.content.res.Resources +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.ConcatAdapter +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.StaggeredGridLayoutManager +import com.xiaoniu.qqversionlist.databinding.RecycleQqVersionBinding +import com.xiaoniu.qqversionlist.util.pxToDp + +class QQVersionListFragmentAdapter : Fragment() { + private var _fragmentBinding: RecycleQqVersionBinding? = null + private val fragmentBinding get() = _fragmentBinding!! + private lateinit var thisActivity: MainActivity + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + _fragmentBinding = RecycleQqVersionBinding.inflate(inflater, container, false) + val view = fragmentBinding.root + thisActivity = requireActivity() as MainActivity + return view + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + versionListStaggeredGridLayout() + fragmentBinding.rvContent.addOnScrollListener(object : RecyclerView.OnScrollListener() { + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + super.onScrolled(recyclerView, dx, dy) + handleScroll(dy) + } + }) + } + + fun versionListStaggeredGridLayout() { + fragmentBinding.rvContent.apply { + val concatenated = + ConcatAdapter(thisActivity.localQQAdapter, thisActivity.versionAdapter) + adapter = concatenated + val screenWidthDp = (Resources.getSystem().displayMetrics.widthPixels).pxToDp + val screenHeightDp = (Resources.getSystem().displayMetrics.heightPixels).pxToDp + layoutManager = if (screenHeightDp >= 600) { + when { + screenWidthDp in 600..840 -> StaggeredGridLayoutManager( + 2, StaggeredGridLayoutManager.VERTICAL + ) + + screenWidthDp > 840 -> StaggeredGridLayoutManager( + 3, StaggeredGridLayoutManager.VERTICAL + ) + + else -> LinearLayoutManager(thisActivity) + } + } else LinearLayoutManager(thisActivity) + } + } + + private fun handleScroll(dy: Int) { + if (dy > 0) thisActivity.binding.btnGuess.shrink() + else if (dy < 0) thisActivity.binding.btnGuess.extend() + } + + override fun onDestroyView() { + super.onDestroyView() + _fragmentBinding = null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/ui/ShiplyAdvancedConfigSheetFragment.kt b/app/src/main/java/com/xiaoniu/qqversionlist/ui/ShiplyAdvancedConfigSheetFragment.kt new file mode 100644 index 0000000..5702697 --- /dev/null +++ b/app/src/main/java/com/xiaoniu/qqversionlist/ui/ShiplyAdvancedConfigSheetFragment.kt @@ -0,0 +1,114 @@ +package com.xiaoniu.qqversionlist.ui + +import android.os.Build +import android.os.Build.VERSION.SDK_INT +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.inputmethod.InputMethodManager +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity.INPUT_METHOD_SERVICE +import com.google.android.material.bottomsheet.BottomSheetBehavior +import com.google.android.material.bottomsheet.BottomSheetDialog +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import com.xiaoniu.qqversionlist.R +import com.xiaoniu.qqversionlist.TipTimeApplication.Companion.SHIPLY_DEFAULT_APPID +import com.xiaoniu.qqversionlist.TipTimeApplication.Companion.SHIPLY_DEFAULT_SDK_VERSION +import com.xiaoniu.qqversionlist.databinding.BottomsheetShiplyAdvancedConfigBinding +import com.xiaoniu.qqversionlist.util.DataStoreUtil +import java.util.Locale + +class ShiplyAdvancedConfigSheetFragment : BottomSheetDialogFragment() { + private lateinit var shiplyAdvancedConfigSheetBinding: BottomsheetShiplyAdvancedConfigBinding + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View = inflater.inflate(R.layout.bottomsheet_shiply_advanced_config, container, false) + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + dialog?.setCanceledOnTouchOutside(false) + shiplyAdvancedConfigSheetBinding = BottomsheetShiplyAdvancedConfigBinding.bind(view) + val shiplyAdvancedConfigSheetBehavior = (this.dialog as BottomSheetDialog).behavior + shiplyAdvancedConfigSheetBehavior.isDraggable = false + this@ShiplyAdvancedConfigSheetFragment.isCancelable = true + shiplyAdvancedConfigSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED + this@ShiplyAdvancedConfigSheetFragment.isCancelable = false + shiplyAdvancedConfigSheetBinding.apply { + shiplyAppid.helperText = + getString(R.string.shiplyGeneralOptionalHelpText) + SHIPLY_DEFAULT_APPID + shiplyModel.helperText = + getString(R.string.shiplyGeneralOptionalHelpText) + Build.MODEL.toString() + shiplyOsVersion.helperText = + getString(R.string.shiplyGeneralOptionalHelpText) + SDK_INT.toString() + shiplySdkVersion.helperText = + getString(R.string.shiplyGeneralOptionalHelpText) + SHIPLY_DEFAULT_SDK_VERSION + shiplyLanguage.helperText = + getString(R.string.shiplyGeneralOptionalHelpText) + Locale.getDefault().language.toString() + + DataStoreUtil.apply { + shiplyAppid.editText?.setText(getString("shiplyAppid", "")) + shiplyOsVersion.editText?.setText( + getString("shiplyOsVersion", "") + ) + shiplyModel.editText?.setText(getString("shiplyModel", "")) + shiplySdkVersion.editText?.setText( + getString("shiplySdkVersion", "") + ) + shiplyLanguage.editText?.setText( + getString("shiplyLanguage", "") + ) + + btnShiplyConfigSave.setOnClickListener { + shiplyAppid.clearFocus() + shiplyOsVersion.clearFocus() + shiplyModel.clearFocus() + shiplySdkVersion.clearFocus() + shiplyLanguage.clearFocus() + val imm = + requireContext().getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(shiplyLanguage.windowToken, 0) + putStringAsync( + "shiplyAppid", shiplyAppid.editText?.text.toString() + ) + putStringAsync( + "shiplyOsVersion", shiplyOsVersion.editText?.text.toString() + ) + putStringAsync( + "shiplyModel", shiplyModel.editText?.text.toString() + ) + putStringAsync( + "shiplySdkVersion", shiplySdkVersion.editText?.text.toString() + ) + putStringAsync( + "shiplyLanguage", shiplyLanguage.editText?.text.toString() + ) + Toast.makeText(requireContext(), R.string.saved, Toast.LENGTH_SHORT).show() + this@ShiplyAdvancedConfigSheetFragment.isCancelable = true + shiplyAdvancedConfigSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN + } + } + + btnShiplyConfigBack.setOnClickListener { + val imm = + requireContext().getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(shiplyLanguage.windowToken, 0) + this@ShiplyAdvancedConfigSheetFragment.isCancelable = true + shiplyAdvancedConfigSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN + } + + dragHandleView.setOnClickListener { + val imm = + requireContext().getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(shiplyLanguage.windowToken, 0) + this@ShiplyAdvancedConfigSheetFragment.isCancelable = true + shiplyAdvancedConfigSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN + } + } + } + + companion object { + const val TAG = "ShiplyAdvancedConfigSheet" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/ui/VersionAdapter.kt b/app/src/main/java/com/xiaoniu/qqversionlist/ui/VersionAdapter.kt index 08ab2cc..d880dbd 100644 --- a/app/src/main/java/com/xiaoniu/qqversionlist/ui/VersionAdapter.kt +++ b/app/src/main/java/com/xiaoniu/qqversionlist/ui/VersionAdapter.kt @@ -134,6 +134,7 @@ class VersionAdapter : ListAdapter(Versi bindDisplayInstall(tvInstall, tvInstallCard, bean) bindVersionTCloud(tvVersion, holder.context) bindAccessibilityTag(accessibilityTag, holder.context, bean) + bindQQNTTag(qqntTag,bean) } } @@ -167,6 +168,7 @@ class VersionAdapter : ListAdapter(Versi bindDisplayInstall(tvOldInstall, tvOldInstallCard, bean) bindVersionTCloud(tvOldVersion, holder.context) bindAccessibilityTag(accessibilityOldTag, holder.context, bean) + bindQQNTTag(qqntOldTag,bean) bindProgress( listDetailProgressLine, @@ -236,7 +238,7 @@ class VersionAdapter : ListAdapter(Versi if (bean.displayInstall) { tvInstallCard.isVisible = true tvInstall.text = tvInstall.context.getString(R.string.installed) - if (bean.isAccessibility) { + if (bean.isAccessibility|| bean.isQQNTFramework) { val marginLayoutParams = tvInstallCard.layoutParams as ViewGroup.MarginLayoutParams marginLayoutParams.marginStart = 3.dp tvInstallCard.layoutParams = marginLayoutParams @@ -261,6 +263,13 @@ class VersionAdapter : ListAdapter(Versi } else accessibilityTag.isVisible = false } + private fun bindQQNTTag( + qqntTag: ImageView, bean: QQVersionBean + ){ + if (bean.isQQNTFramework) qqntTag.isVisible = true + else qqntTag.isVisible = false + } + private fun bindVersionTCloud( tvVersion: TextView, context: Context ) { diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/ui/VersionListPagerAdapter.kt b/app/src/main/java/com/xiaoniu/qqversionlist/ui/VersionListPagerAdapter.kt new file mode 100644 index 0000000..f305f9a --- /dev/null +++ b/app/src/main/java/com/xiaoniu/qqversionlist/ui/VersionListPagerAdapter.kt @@ -0,0 +1,22 @@ +package com.xiaoniu.qqversionlist.ui + +import android.content.Context +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentActivity +import androidx.viewpager2.adapter.FragmentStateAdapter + +class VersionListPagerAdapter(private val context: Context) : + FragmentStateAdapter(context as FragmentActivity) { + override fun getItemCount(): Int = 1 + + override fun createFragment(position: Int): Fragment { + return QQVersionListFragmentAdapter() + } + + fun getFragementAtPosition(position: Int): QQVersionListFragmentAdapter? { + return when (position) { + 0 -> QQVersionListFragmentAdapter() + else -> null + } + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/alert_line.xml b/app/src/main/res/drawable/alert_line.xml index 4643b2a..7c28256 100644 --- a/app/src/main/res/drawable/alert_line.xml +++ b/app/src/main/res/drawable/alert_line.xml @@ -1,9 +1,24 @@ + - + diff --git a/app/src/main/res/drawable/apps_line.xml b/app/src/main/res/drawable/apps_line.xml index 3fb6140..b57c32f 100644 --- a/app/src/main/res/drawable/apps_line.xml +++ b/app/src/main/res/drawable/apps_line.xml @@ -1,3 +1,18 @@ + + + + + + diff --git a/app/src/main/res/drawable/arrow_right_s_line.xml b/app/src/main/res/drawable/arrow_right_s_line.xml index a2c103d..5095471 100644 --- a/app/src/main/res/drawable/arrow_right_s_line.xml +++ b/app/src/main/res/drawable/arrow_right_s_line.xml @@ -1,3 +1,18 @@ + + + + + + diff --git a/app/src/main/res/drawable/braces_line.xml b/app/src/main/res/drawable/braces_line.xml index 2cf6ecb..84dd5a9 100644 --- a/app/src/main/res/drawable/braces_line.xml +++ b/app/src/main/res/drawable/braces_line.xml @@ -1,3 +1,18 @@ + - - - - diff --git a/app/src/main/res/drawable/ic_up.xml b/app/src/main/res/drawable/ic_up.xml deleted file mode 100644 index c3524df..0000000 --- a/app/src/main/res/drawable/ic_up.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/information_line.xml b/app/src/main/res/drawable/information_line.xml index 906e1e4..38cf6cb 100644 --- a/app/src/main/res/drawable/information_line.xml +++ b/app/src/main/res/drawable/information_line.xml @@ -1,3 +1,18 @@ + + + + + + + diff --git a/app/src/main/res/drawable/question_line.xml b/app/src/main/res/drawable/question_line.xml index 9977a01..e65cb4f 100644 --- a/app/src/main/res/drawable/question_line.xml +++ b/app/src/main/res/drawable/question_line.xml @@ -1,3 +1,18 @@ + + + @@ -174,7 +187,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:contentDescription="@string/versionCardExpandButtonContentDescription" - app:icon="@drawable/ic_down" + app:icon="@drawable/arrow_down_s_line" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> diff --git a/app/src/main/res/layout/item_version_detail.xml b/app/src/main/res/layout/item_version_detail.xml index c2815fb..c1aaf37 100644 --- a/app/src/main/res/layout/item_version_detail.xml +++ b/app/src/main/res/layout/item_version_detail.xml @@ -56,6 +56,19 @@ app:layout_constraintTop_toTopOf="parent" tools:text="9.0.25" /> + + @@ -243,7 +256,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:contentDescription="@string/versionCardCollapseButtonContentDescription" - app:icon="@drawable/ic_up" + app:icon="@drawable/arrow_up_s_line" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> diff --git a/app/src/main/res/values-ar-rSA/strings.xml b/app/src/main/res/values-ar-rSA/strings.xml index 3c50085..576d357 100644 --- a/app/src/main/res/values-ar-rSA/strings.xml +++ b/app/src/main/res/values-ar-rSA/strings.xml @@ -128,4 +128,5 @@ 下载 停止 跳过 + 基于 QQNT 技术架构 diff --git a/app/src/main/res/values-en-rUS/strings.xml b/app/src/main/res/values-en-rUS/strings.xml index 0e80c12..2049a02 100644 --- a/app/src/main/res/values-en-rUS/strings.xml +++ b/app/src/main/res/values-en-rUS/strings.xml @@ -128,4 +128,5 @@ Download Stop Skip + Powered by QQNT Framework diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml index 3c50085..576d357 100644 --- a/app/src/main/res/values-es-rES/strings.xml +++ b/app/src/main/res/values-es-rES/strings.xml @@ -128,4 +128,5 @@ 下载 停止 跳过 + 基于 QQNT 技术架构 diff --git a/app/src/main/res/values-fr-rFR/strings.xml b/app/src/main/res/values-fr-rFR/strings.xml index 2575e03..c83a37c 100644 --- a/app/src/main/res/values-fr-rFR/strings.xml +++ b/app/src/main/res/values-fr-rFR/strings.xml @@ -128,4 +128,5 @@ 下载 停止 跳过 + 基于 QQNT 技术架构 diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index 3c50085..576d357 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -128,4 +128,5 @@ 下载 停止 跳过 + 基于 QQNT 技术架构 diff --git a/app/src/main/res/values-ko-rKR/strings.xml b/app/src/main/res/values-ko-rKR/strings.xml index 3c50085..576d357 100644 --- a/app/src/main/res/values-ko-rKR/strings.xml +++ b/app/src/main/res/values-ko-rKR/strings.xml @@ -128,4 +128,5 @@ 下载 停止 跳过 + 基于 QQNT 技术架构 diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml index 3c50085..576d357 100644 --- a/app/src/main/res/values-ru-rRU/strings.xml +++ b/app/src/main/res/values-ru-rRU/strings.xml @@ -128,4 +128,5 @@ 下载 停止 跳过 + 基于 QQNT 技术架构 diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 3c50085..576d357 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -128,4 +128,5 @@ 下载 停止 跳过 + 基于 QQNT 技术架构 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 3e83a8f..8d0746f 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -128,4 +128,5 @@ 下載 停止 跳過 + 基於 QQNT 技術架構 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 77f77a1..bd4296c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -127,4 +127,5 @@ 下载 停止 跳过 + 基于 QQNT 技术架构 \ No newline at end of file From 92e79659a6b211f90d6da8d00797d8fada39c74c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E9=B2=AB=E9=9B=AA=E7=8B=90?= <139336664+ArcticFoxPro@users.noreply.github.com> Date: Sun, 8 Sep 2024 10:31:45 +0800 Subject: [PATCH 04/23] =?UTF-8?q?=E5=B7=B2=E5=9C=A8=E7=9B=B8=E5=85=B3UI?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=AD=E6=B7=BB=E5=8A=A0AGPL-3.0=E8=AE=B8?= =?UTF-8?q?=E5=8F=AF=E5=A4=B4=EF=BC=8C=E4=BB=A5=E7=AC=A6=E5=90=88=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=88=86=E5=8F=91=E8=A6=81=E6=B1=82=EF=BC=8C=E5=B9=B6?= =?UTF-8?q?=E6=8F=90=E5=8D=87=E5=BC=80=E6=BA=90=E5=90=88=E8=A7=84=E6=80=A7?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xiaoniu/qqversionlist/ui/LocalQQAdapter.kt | 18 ++++++++++++++++++ .../ui/QQVersionListFragmentAdapter.kt | 18 ++++++++++++++++++ .../ui/ShiplyAdvancedConfigSheetFragment.kt | 18 ++++++++++++++++++ .../ui/VersionListPagerAdapter.kt | 18 ++++++++++++++++++ 4 files changed, 72 insertions(+) diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/ui/LocalQQAdapter.kt b/app/src/main/java/com/xiaoniu/qqversionlist/ui/LocalQQAdapter.kt index 3e475c2..2c67ff1 100644 --- a/app/src/main/java/com/xiaoniu/qqversionlist/ui/LocalQQAdapter.kt +++ b/app/src/main/java/com/xiaoniu/qqversionlist/ui/LocalQQAdapter.kt @@ -1,3 +1,21 @@ +/* + QQ Versions Tool for Android™ + Copyright (C) 2023 klxiaoniu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + package com.xiaoniu.qqversionlist.ui import android.annotation.SuppressLint diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/ui/QQVersionListFragmentAdapter.kt b/app/src/main/java/com/xiaoniu/qqversionlist/ui/QQVersionListFragmentAdapter.kt index 7be1d65..d616fbe 100644 --- a/app/src/main/java/com/xiaoniu/qqversionlist/ui/QQVersionListFragmentAdapter.kt +++ b/app/src/main/java/com/xiaoniu/qqversionlist/ui/QQVersionListFragmentAdapter.kt @@ -1,3 +1,21 @@ +/* + QQ Versions Tool for Android™ + Copyright (C) 2023 klxiaoniu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + package com.xiaoniu.qqversionlist.ui import android.content.res.Resources diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/ui/ShiplyAdvancedConfigSheetFragment.kt b/app/src/main/java/com/xiaoniu/qqversionlist/ui/ShiplyAdvancedConfigSheetFragment.kt index 5702697..f17a281 100644 --- a/app/src/main/java/com/xiaoniu/qqversionlist/ui/ShiplyAdvancedConfigSheetFragment.kt +++ b/app/src/main/java/com/xiaoniu/qqversionlist/ui/ShiplyAdvancedConfigSheetFragment.kt @@ -1,3 +1,21 @@ +/* + QQ Versions Tool for Android™ + Copyright (C) 2023 klxiaoniu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + package com.xiaoniu.qqversionlist.ui import android.os.Build diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/ui/VersionListPagerAdapter.kt b/app/src/main/java/com/xiaoniu/qqversionlist/ui/VersionListPagerAdapter.kt index f305f9a..273e17d 100644 --- a/app/src/main/java/com/xiaoniu/qqversionlist/ui/VersionListPagerAdapter.kt +++ b/app/src/main/java/com/xiaoniu/qqversionlist/ui/VersionListPagerAdapter.kt @@ -1,3 +1,21 @@ +/* + QQ Versions Tool for Android™ + Copyright (C) 2023 klxiaoniu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + package com.xiaoniu.qqversionlist.ui import android.content.Context From c3f193783ff0bdbede222bcb64df8a55b8042239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E9=B2=AB=E9=9B=AA=E7=8B=90?= <139336664+ArcticFoxPro@users.noreply.github.com> Date: Sun, 8 Sep 2024 11:48:46 +0800 Subject: [PATCH 05/23] =?UTF-8?q?fix(qqversionlist):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=A4=9A=E7=AA=97=E5=8F=A3=E6=A8=A1=E5=BC=8F=E4=B8=8B=E7=9A=84?= =?UTF-8?q?=E5=B8=83=E5=B1=80=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在`QQVersionListFragmentAdapter`中修复了导致多窗口模式下布局参数错误的问题。现在通过更新方法签名来确保`versionListStaggeredGridLayout`在配置更改时正确处理布局。 --- .../xiaoniu/qqversionlist/ui/MainActivity.kt | 4 ++-- .../ui/QQVersionListFragmentAdapter.kt | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/ui/MainActivity.kt b/app/src/main/java/com/xiaoniu/qqversionlist/ui/MainActivity.kt index 0c8eff4..b1607d1 100644 --- a/app/src/main/java/com/xiaoniu/qqversionlist/ui/MainActivity.kt +++ b/app/src/main/java/com/xiaoniu/qqversionlist/ui/MainActivity.kt @@ -163,12 +163,12 @@ class MainActivity : AppCompatActivity() { override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) - recycleViewFragmentAdapter.versionListStaggeredGridLayout() + recycleViewFragmentAdapter.versionListStaggeredGridLayout(this) } override fun onMultiWindowModeChanged(isInMultiWindowMode: Boolean, newConfig: Configuration) { super.onMultiWindowModeChanged(isInMultiWindowMode, newConfig) - recycleViewFragmentAdapter.versionListStaggeredGridLayout() + recycleViewFragmentAdapter.versionListStaggeredGridLayout(this) } private fun showUADialog(agreed: Boolean, UATarget: Int) { diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/ui/QQVersionListFragmentAdapter.kt b/app/src/main/java/com/xiaoniu/qqversionlist/ui/QQVersionListFragmentAdapter.kt index d616fbe..fecc80e 100644 --- a/app/src/main/java/com/xiaoniu/qqversionlist/ui/QQVersionListFragmentAdapter.kt +++ b/app/src/main/java/com/xiaoniu/qqversionlist/ui/QQVersionListFragmentAdapter.kt @@ -31,23 +31,24 @@ import androidx.recyclerview.widget.StaggeredGridLayoutManager import com.xiaoniu.qqversionlist.databinding.RecycleQqVersionBinding import com.xiaoniu.qqversionlist.util.pxToDp +// 将视图绑定放在 Fragment 前声明,否则在旋转屏幕时会导致 Fragment 里的数据销毁 +// 相信用户内存的力量(逃) +private var _fragmentBinding: RecycleQqVersionBinding? = null + class QQVersionListFragmentAdapter : Fragment() { - private var _fragmentBinding: RecycleQqVersionBinding? = null private val fragmentBinding get() = _fragmentBinding!! - private lateinit var thisActivity: MainActivity override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { _fragmentBinding = RecycleQqVersionBinding.inflate(inflater, container, false) val view = fragmentBinding.root - thisActivity = requireActivity() as MainActivity return view } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - versionListStaggeredGridLayout() + versionListStaggeredGridLayout(requireActivity() as MainActivity) fragmentBinding.rvContent.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) @@ -56,13 +57,12 @@ class QQVersionListFragmentAdapter : Fragment() { }) } - fun versionListStaggeredGridLayout() { + fun versionListStaggeredGridLayout(thisActivity: MainActivity) { + val concatenated = ConcatAdapter(thisActivity.localQQAdapter, thisActivity.versionAdapter) + val screenWidthDp = (Resources.getSystem().displayMetrics.widthPixels).pxToDp + val screenHeightDp = (Resources.getSystem().displayMetrics.heightPixels).pxToDp fragmentBinding.rvContent.apply { - val concatenated = - ConcatAdapter(thisActivity.localQQAdapter, thisActivity.versionAdapter) adapter = concatenated - val screenWidthDp = (Resources.getSystem().displayMetrics.widthPixels).pxToDp - val screenHeightDp = (Resources.getSystem().displayMetrics.heightPixels).pxToDp layoutManager = if (screenHeightDp >= 600) { when { screenWidthDp in 600..840 -> StaggeredGridLayoutManager( @@ -80,6 +80,7 @@ class QQVersionListFragmentAdapter : Fragment() { } private fun handleScroll(dy: Int) { + val thisActivity = requireActivity() as MainActivity if (dy > 0) thisActivity.binding.btnGuess.shrink() else if (dy < 0) thisActivity.binding.btnGuess.extend() } From 7574b71f98f41c00ba83b547527ae4b0f16c0df8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E9=B2=AB=E9=9B=AA=E7=8B=90?= <139336664+ArcticFoxPro@users.noreply.github.com> Date: Mon, 9 Sep 2024 13:23:37 +0800 Subject: [PATCH 06/23] =?UTF-8?q?refactor(app):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=AD=98=E5=82=A8=E5=92=8C=E9=80=82=E9=85=8D?= =?UTF-8?q?=E5=99=A8=E5=91=BD=E5=90=8D=EF=BC=8C=E6=9B=B4=E6=96=B0=E4=B8=BB?= =?UTF-8?q?=E9=A2=98=E4=BB=A5=E6=94=AF=E6=8C=81=E5=8A=A8=E6=80=81=E9=A2=9C?= =?UTF-8?q?=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 重构SharedPreferences迁移至DataStore,更名SpUtil为DataStoreUtil。 - 将VersionAdapter重命名为QQVersionAdapter,以明确其展示QQ版本的用途。 - 主题更新,支持暗黑模式下的动态颜色切换,提升夜间模式的用户体验。 - 引入TIMVersionBean数据类和相关解析工具类,为TIM版本信息处理打下基础。 --- app/build.gradle.kts | 2 +- .../qqversionlist/data/TIMVersionBean.kt | 17 + .../xiaoniu/qqversionlist/ui/MainActivity.kt | 91 ++-- ...{VersionAdapter.kt => QQVersionAdapter.kt} | 54 +-- .../ui/QQVersionListFragmentAdapter.kt | 12 +- .../qqversionlist/ui/ShiplyUrlListAdapter.kt | 2 +- .../ui/VersionListPagerAdapter.kt | 2 +- .../util/{SpUtil.kt => DataStoreUtil.kt} | 379 ++++++++-------- .../xiaoniu/qqversionlist/util/Extensions.kt | 6 +- .../qqversionlist/util/QQVersionBeanUtil.kt | 46 ++ .../qqversionlist/util/TIMVersionBeanUtil.kt | 105 +++++ .../{item_version.xml => item_qq_version.xml} | 418 +++++++++--------- ..._detail.xml => item_qq_version_detail.xml} | 0 app/src/main/res/values-night-v27/themes.xml | 2 +- app/src/main/res/values-night-v31/themes.xml | 2 +- app/src/main/res/values-night/themes.xml | 2 +- app/src/main/res/values-v27/themes.xml | 2 +- app/src/main/res/values-v31/themes.xml | 2 +- app/src/main/res/values/themes.xml | 2 +- 19 files changed, 653 insertions(+), 493 deletions(-) create mode 100644 app/src/main/java/com/xiaoniu/qqversionlist/data/TIMVersionBean.kt rename app/src/main/java/com/xiaoniu/qqversionlist/ui/{VersionAdapter.kt => QQVersionAdapter.kt} (91%) rename app/src/main/java/com/xiaoniu/qqversionlist/util/{SpUtil.kt => DataStoreUtil.kt} (93%) create mode 100644 app/src/main/java/com/xiaoniu/qqversionlist/util/QQVersionBeanUtil.kt create mode 100644 app/src/main/java/com/xiaoniu/qqversionlist/util/TIMVersionBeanUtil.kt rename app/src/main/res/layout/{item_version.xml => item_qq_version.xml} (98%) rename app/src/main/res/layout/{item_version_detail.xml => item_qq_version_detail.xml} (100%) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index d9c9cba..d5f9729 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -92,7 +92,7 @@ android { dependencies { implementation("androidx.core:core-ktx:1.13.1") - implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.4") + implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.5") implementation("androidx.appcompat:appcompat:1.7.0") implementation("androidx.core:core-splashscreen:1.1.0-rc01") implementation("com.google.android.material:material:1.12.0") diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/data/TIMVersionBean.kt b/app/src/main/java/com/xiaoniu/qqversionlist/data/TIMVersionBean.kt new file mode 100644 index 0000000..4e67cd2 --- /dev/null +++ b/app/src/main/java/com/xiaoniu/qqversionlist/data/TIMVersionBean.kt @@ -0,0 +1,17 @@ +package com.xiaoniu.qqversionlist.data + +import kotlinx.serialization.Serializable + +@Serializable +data class TIMVersionBean( + val version: String, + val datetime: String, + val fix: List, + val new: String, + + var jsonString: String = "", + var displayType: Int = 0, // 0为收起 + var displayInstall: Boolean = false, // false 为不展示 + var isAccessibility: Boolean = false, + var isQQNTFramework: Boolean = false +) diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/ui/MainActivity.kt b/app/src/main/java/com/xiaoniu/qqversionlist/ui/MainActivity.kt index b1607d1..c2f4bf8 100644 --- a/app/src/main/java/com/xiaoniu/qqversionlist/ui/MainActivity.kt +++ b/app/src/main/java/com/xiaoniu/qqversionlist/ui/MainActivity.kt @@ -36,6 +36,7 @@ import android.text.SpannableString import android.text.TextWatcher import android.text.style.URLSpan import android.util.Base64 +import android.util.Log import android.view.MenuItem import android.view.View import android.view.ViewGroup @@ -62,10 +63,10 @@ import com.google.gson.GsonBuilder import com.google.gson.JsonElement import com.xiaoniu.qqversionlist.BuildConfig import com.xiaoniu.qqversionlist.R -import com.xiaoniu.qqversionlist.TipTimeApplication.Companion.EARLIEST_QQNT_FRAMEWORK_VERSION_STABLE import com.xiaoniu.qqversionlist.TipTimeApplication.Companion.SHIPLY_DEFAULT_APPID import com.xiaoniu.qqversionlist.TipTimeApplication.Companion.SHIPLY_DEFAULT_SDK_VERSION import com.xiaoniu.qqversionlist.data.QQVersionBean +import com.xiaoniu.qqversionlist.data.TIMVersionBean import com.xiaoniu.qqversionlist.databinding.ActivityMainBinding import com.xiaoniu.qqversionlist.databinding.DialogAboutBinding import com.xiaoniu.qqversionlist.databinding.DialogGuessBinding @@ -81,17 +82,17 @@ import com.xiaoniu.qqversionlist.util.ClipboardUtil.copyText import com.xiaoniu.qqversionlist.util.DataStoreUtil import com.xiaoniu.qqversionlist.util.InfoUtil.dialogError import com.xiaoniu.qqversionlist.util.InfoUtil.showToast +import com.xiaoniu.qqversionlist.util.QQVersionBeanUtil.qqVersionBeanUtil import com.xiaoniu.qqversionlist.util.ShiplyUtil import com.xiaoniu.qqversionlist.util.StringUtil.getAllAPKUrl import com.xiaoniu.qqversionlist.util.StringUtil.toPrettyFormat +import com.xiaoniu.qqversionlist.util.TIMVersionBeanUtil.timVersionBeanUtil import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import kotlinx.serialization.json.Json import okhttp3.OkHttpClient import okhttp3.Request -import org.apache.maven.artifact.versioning.DefaultArtifactVersion import java.io.BufferedReader import java.io.ByteArrayInputStream import java.io.InputStreamReader @@ -102,10 +103,11 @@ import java.util.zip.GZIPInputStream class MainActivity : AppCompatActivity() { lateinit var binding: ActivityMainBinding - lateinit var versionAdapter: VersionAdapter + lateinit var qqVersionAdapter: QQVersionAdapter lateinit var localQQAdapter: LocalQQAdapter - private lateinit var qqVersion: List - private lateinit var recycleViewFragmentAdapter: QQVersionListFragmentAdapter + lateinit var qqVersion: List + lateinit var timVersion: List + private lateinit var qqVersionListFragmentAdapter: QQVersionListFragmentAdapter private lateinit var rvPagerAdapter: VersionListPagerAdapter override fun onCreate(savedInstanceState: Bundle?) { @@ -139,17 +141,17 @@ class MainActivity : AppCompatActivity() { WindowCompat.setDecorFitsSystemWindows(window, false) - versionAdapter = VersionAdapter() + qqVersionAdapter = QQVersionAdapter() localQQAdapter = LocalQQAdapter() binding.rvPager.adapter = VersionListPagerAdapter(this) rvPagerAdapter = binding.rvPager.adapter as VersionListPagerAdapter - recycleViewFragmentAdapter = QQVersionListFragmentAdapter() + qqVersionListFragmentAdapter = QQVersionListFragmentAdapter() initButtons() binding.rvPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { override fun onPageSelected(position: Int) { super.onPageSelected(position) - recycleViewFragmentAdapter = + qqVersionListFragmentAdapter = rvPagerAdapter.getFragementAtPosition(position) as QQVersionListFragmentAdapter } }) @@ -163,12 +165,12 @@ class MainActivity : AppCompatActivity() { override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) - recycleViewFragmentAdapter.versionListStaggeredGridLayout(this) + qqVersionListFragmentAdapter.versionListStaggeredGridLayout(this) } override fun onMultiWindowModeChanged(isInMultiWindowMode: Boolean, newConfig: Configuration) { super.onMultiWindowModeChanged(isInMultiWindowMode, newConfig) - recycleViewFragmentAdapter.versionListStaggeredGridLayout(this) + qqVersionListFragmentAdapter.versionListStaggeredGridLayout(this) } private fun showUADialog(agreed: Boolean, UATarget: Int) { @@ -432,21 +434,21 @@ class MainActivity : AppCompatActivity() { ) else qqVersionBean } - versionAdapter.submitList(qqVersion) + qqVersionAdapter.submitList(qqVersion) } // 下两个设置不能异步持久化存储,否则视图更新读不到更新值 progressSize.setOnCheckedChangeListener { _, isChecked -> DataStoreUtil.putBoolean("progressSize", isChecked) - versionAdapter.updateItemProperty("isShowProgressSize") + qqVersionAdapter.updateItemProperty("isShowProgressSize") } versionTcloud.setOnCheckedChangeListener { _, isChecked -> DataStoreUtil.putBoolean("versionTCloud", isChecked) dialogPersonalization.versionTcloudThickness.setEnabled( isChecked ) - versionAdapter.updateItemProperty("isTCloud") + qqVersionAdapter.updateItemProperty("isTCloud") } btnPersonalizationOk.setOnClickListener { dialogPer.dismiss() @@ -479,7 +481,7 @@ class MainActivity : AppCompatActivity() { "versionTCloudThickness", "System" ) } - versionAdapter.updateItemProperty("isTCloud") + qqVersionAdapter.updateItemProperty("isTCloud") } } } @@ -1056,42 +1058,9 @@ class MainActivity : AppCompatActivity() { val response = okHttpClient.newCall(request).execute() val responseData = response.body?.string() if (responseData != null) { - val start = (responseData.indexOf("versions64\":[")) + 12 - val end = (responseData.indexOf(";\n" + " typeof")) - val totalJson = responseData.substring(start, end) - qqVersion = totalJson.split("},{").reversed().map { - val pstart = it.indexOf("{\"versions") - val pend = it.indexOf(",\"length") - val json = it.substring(pstart, pend) - Json.decodeFromString(json).apply { - jsonString = json - // 标记本机 Android QQ 版本 - this.displayInstall = (DataStoreUtil.getString( - "QQVersionInstall", "" - ) == this.versionNumber) - this.isAccessibility = false - // 无障碍标记 - /*DefaultArtifactVersion(this.versionNumber) >= DefaultArtifactVersion( - EARLIEST_ACCESSIBILITY_VERSION - )*/ - - this.isQQNTFramework = - DefaultArtifactVersion(this.versionNumber) >= DefaultArtifactVersion( - EARLIEST_QQNT_FRAMEWORK_VERSION_STABLE - ) - } - } - if (DataStoreUtil.getBoolean( - "displayFirst", true - ) - ) qqVersion[0].displayType = 1 - // 舍弃 currentQQVersion = qqVersion.first().versionNumber - // 大版本号也放持久化存储了,否则猜版 Shortcut 因为加载过快而获取不到东西 - DataStoreUtil.putStringAsync( - "versionBig", qqVersion.first().versionNumber - ) + qqVersionBeanUtil(this@MainActivity, responseData) withContext(Dispatchers.Main) { - versionAdapter.submitList(qqVersion) + qqVersionAdapter.submitList(qqVersion) } } } catch (e: Exception) { @@ -1103,6 +1072,28 @@ class MainActivity : AppCompatActivity() { if (menu != null) menu.isEnabled = true } } + try { + val okHttpClient = OkHttpClient() + val request = + Request.Builder().url("https://im.qq.com/rainbow/TIMDownload/") + .build() + val response = okHttpClient.newCall(request).execute() + val responseData = response.body?.string() + if (responseData != null) { + timVersionBeanUtil(this@MainActivity, responseData) + // withContext(Dispatchers.Main) { + // timVersionAdapter.submitList(timVersion) + // } + } + } catch (e: Exception) { + e.printStackTrace() + dialogError(e) + } finally { + withContext(Dispatchers.Main) { + binding.progressLine.hide() + if (menu != null) menu.isEnabled = true + } + } } } } diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/ui/VersionAdapter.kt b/app/src/main/java/com/xiaoniu/qqversionlist/ui/QQVersionAdapter.kt similarity index 91% rename from app/src/main/java/com/xiaoniu/qqversionlist/ui/VersionAdapter.kt rename to app/src/main/java/com/xiaoniu/qqversionlist/ui/QQVersionAdapter.kt index d880dbd..1340690 100644 --- a/app/src/main/java/com/xiaoniu/qqversionlist/ui/VersionAdapter.kt +++ b/app/src/main/java/com/xiaoniu/qqversionlist/ui/QQVersionAdapter.kt @@ -40,22 +40,22 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.progressindicator.LinearProgressIndicator import com.xiaoniu.qqversionlist.R import com.xiaoniu.qqversionlist.data.QQVersionBean -import com.xiaoniu.qqversionlist.databinding.ItemVersionBinding -import com.xiaoniu.qqversionlist.databinding.ItemVersionDetailBinding +import com.xiaoniu.qqversionlist.databinding.ItemQqVersionBinding +import com.xiaoniu.qqversionlist.databinding.ItemQqVersionDetailBinding import com.xiaoniu.qqversionlist.util.DataStoreUtil import com.xiaoniu.qqversionlist.util.StringUtil.toPrettyFormat -import com.xiaoniu.qqversionlist.util.dp +import com.xiaoniu.qqversionlist.util.Extensions.dp private var getProgressSize = DataStoreUtil.getBoolean("progressSize", false) private var getVersionTCloud = DataStoreUtil.getBoolean("versionTCloud", true) private var getVersionTCloudThickness = DataStoreUtil.getString("versionTCloudThickness", "System") -class VersionAdapter : ListAdapter(VersionDiffCallback()) { +class QQVersionAdapter : ListAdapter(QQVersionDiffCallback()) { - class ViewHolder(val binding: ItemVersionBinding, val context: Context) : + class ViewHolder(val binding: ItemQqVersionBinding, val context: Context) : RecyclerView.ViewHolder(binding.root) - class ViewHolderDetail(val binding: ItemVersionDetailBinding, val context: Context) : + class ViewHolderDetail(val binding: ItemQqVersionDetailBinding, val context: Context) : RecyclerView.ViewHolder(binding.root) override fun getItemViewType(position: Int): Int { @@ -66,7 +66,7 @@ class VersionAdapter : ListAdapter(Versi return when (viewType) { 0 -> { ViewHolder( - ItemVersionBinding.inflate( + ItemQqVersionBinding.inflate( LayoutInflater.from(parent.context), parent, false ), parent.context ).apply { @@ -92,7 +92,7 @@ class VersionAdapter : ListAdapter(Versi else -> { ViewHolderDetail( - ItemVersionDetailBinding.inflate( + ItemQqVersionDetailBinding.inflate( LayoutInflater.from(parent.context), parent, false ), parent.context ).apply { @@ -370,26 +370,26 @@ class VersionAdapter : ListAdapter(Versi } } -} - -class VersionDiffCallback : DiffUtil.ItemCallback() { - override fun areItemsTheSame( - oldItem: QQVersionBean, newItem: QQVersionBean - ): Boolean { - return oldItem.versions == newItem.versions - } + class QQVersionDiffCallback : DiffUtil.ItemCallback() { + override fun areItemsTheSame( + oldItem: QQVersionBean, newItem: QQVersionBean + ): Boolean { + return oldItem.versions == newItem.versions + } - override fun areContentsTheSame( - oldItem: QQVersionBean, newItem: QQVersionBean - ): Boolean { - return oldItem.displayType == newItem.displayType && oldItem.displayInstall == newItem.displayInstall - } + override fun areContentsTheSame( + oldItem: QQVersionBean, newItem: QQVersionBean + ): Boolean { + return oldItem.displayType == newItem.displayType && oldItem.displayInstall == newItem.displayInstall + } - override fun getChangePayload( - oldItem: QQVersionBean, newItem: QQVersionBean - ): Any? { - return if (oldItem.displayType != newItem.displayType) "displayType" - else if (oldItem.displayInstall != newItem.displayInstall) "displayInstall" - else null + override fun getChangePayload( + oldItem: QQVersionBean, newItem: QQVersionBean + ): Any? { + return if (oldItem.displayType != newItem.displayType) "displayType" + else if (oldItem.displayInstall != newItem.displayInstall) "displayInstall" + else null + } } } + diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/ui/QQVersionListFragmentAdapter.kt b/app/src/main/java/com/xiaoniu/qqversionlist/ui/QQVersionListFragmentAdapter.kt index fecc80e..3147074 100644 --- a/app/src/main/java/com/xiaoniu/qqversionlist/ui/QQVersionListFragmentAdapter.kt +++ b/app/src/main/java/com/xiaoniu/qqversionlist/ui/QQVersionListFragmentAdapter.kt @@ -29,19 +29,19 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.StaggeredGridLayoutManager import com.xiaoniu.qqversionlist.databinding.RecycleQqVersionBinding -import com.xiaoniu.qqversionlist.util.pxToDp +import com.xiaoniu.qqversionlist.util.Extensions.pxToDp // 将视图绑定放在 Fragment 前声明,否则在旋转屏幕时会导致 Fragment 里的数据销毁 // 相信用户内存的力量(逃) -private var _fragmentBinding: RecycleQqVersionBinding? = null +private var insideFragmentBinding: RecycleQqVersionBinding? = null class QQVersionListFragmentAdapter : Fragment() { - private val fragmentBinding get() = _fragmentBinding!! + private val fragmentBinding get() = insideFragmentBinding!! override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { - _fragmentBinding = RecycleQqVersionBinding.inflate(inflater, container, false) + insideFragmentBinding = RecycleQqVersionBinding.inflate(inflater, container, false) val view = fragmentBinding.root return view } @@ -58,7 +58,7 @@ class QQVersionListFragmentAdapter : Fragment() { } fun versionListStaggeredGridLayout(thisActivity: MainActivity) { - val concatenated = ConcatAdapter(thisActivity.localQQAdapter, thisActivity.versionAdapter) + val concatenated = ConcatAdapter(thisActivity.localQQAdapter, thisActivity.qqVersionAdapter) val screenWidthDp = (Resources.getSystem().displayMetrics.widthPixels).pxToDp val screenHeightDp = (Resources.getSystem().displayMetrics.heightPixels).pxToDp fragmentBinding.rvContent.apply { @@ -87,6 +87,6 @@ class QQVersionListFragmentAdapter : Fragment() { override fun onDestroyView() { super.onDestroyView() - _fragmentBinding = null + insideFragmentBinding = null } } \ No newline at end of file diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/ui/ShiplyUrlListAdapter.kt b/app/src/main/java/com/xiaoniu/qqversionlist/ui/ShiplyUrlListAdapter.kt index 994ef7d..4d4b379 100644 --- a/app/src/main/java/com/xiaoniu/qqversionlist/ui/ShiplyUrlListAdapter.kt +++ b/app/src/main/java/com/xiaoniu/qqversionlist/ui/ShiplyUrlListAdapter.kt @@ -45,7 +45,7 @@ class ShiplyUrlListAdapter(private val urlList: List) : RecyclerView.Adapter() { inner class ShiplyUrlViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val shiplyUrlText = itemView.findViewById(R.id.shiply_url_text) + val shiplyUrlText: TextView = itemView.findViewById(R.id.shiply_url_text) var currentUrl: String? = null init { diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/ui/VersionListPagerAdapter.kt b/app/src/main/java/com/xiaoniu/qqversionlist/ui/VersionListPagerAdapter.kt index 273e17d..0664297 100644 --- a/app/src/main/java/com/xiaoniu/qqversionlist/ui/VersionListPagerAdapter.kt +++ b/app/src/main/java/com/xiaoniu/qqversionlist/ui/VersionListPagerAdapter.kt @@ -23,7 +23,7 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import androidx.viewpager2.adapter.FragmentStateAdapter -class VersionListPagerAdapter(private val context: Context) : +class VersionListPagerAdapter(context: Context) : FragmentStateAdapter(context as FragmentActivity) { override fun getItemCount(): Int = 1 diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/util/SpUtil.kt b/app/src/main/java/com/xiaoniu/qqversionlist/util/DataStoreUtil.kt similarity index 93% rename from app/src/main/java/com/xiaoniu/qqversionlist/util/SpUtil.kt rename to app/src/main/java/com/xiaoniu/qqversionlist/util/DataStoreUtil.kt index e5b0da4..1ae5c29 100644 --- a/app/src/main/java/com/xiaoniu/qqversionlist/util/SpUtil.kt +++ b/app/src/main/java/com/xiaoniu/qqversionlist/util/DataStoreUtil.kt @@ -1,190 +1,189 @@ -/* - QQ Versions Tool for Android™ - Copyright (C) 2023 klxiaoniu - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as - published by the Free Software Foundation, either version 3 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -package com.xiaoniu.qqversionlist.util - -import android.content.Context -import androidx.datastore.core.DataStore -import androidx.datastore.core.IOException -import androidx.datastore.preferences.SharedPreferencesMigration -import androidx.datastore.preferences.core.Preferences -import androidx.datastore.preferences.core.booleanPreferencesKey -import androidx.datastore.preferences.core.doublePreferencesKey -import androidx.datastore.preferences.core.edit -import androidx.datastore.preferences.core.floatPreferencesKey -import androidx.datastore.preferences.core.intPreferencesKey -import androidx.datastore.preferences.core.longPreferencesKey -import androidx.datastore.preferences.core.stringPreferencesKey -import androidx.datastore.preferences.preferencesDataStore -import com.xiaoniu.qqversionlist.TipTimeApplication -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Deferred -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.flow.firstOrNull -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking - -val Context.dataStore: DataStore by preferencesDataStore( - name = "data", - produceMigrations = { context -> - listOf( - SharedPreferencesMigration(context, "data") - ) - }) - -object DataStoreUtil { - private val dataStore: DataStore by lazy { - TipTimeApplication.instance.dataStore - } - - @Throws(IOException::class) - fun getInt(key: String, defValue: Int): Int { - return runBlocking { - dataStore.data.firstOrNull()?.let { preferences -> - preferences[intPreferencesKey(key)] ?: defValue - } ?: defValue - } - } - - @Throws(IOException::class) - fun putInt(key: String, value: Int) { - runBlocking { - dataStore.edit { preferences -> - preferences[intPreferencesKey(key)] = value - } - } - } - - @Throws(IOException::class) - fun getString(key: String, defValue: String): String { - return runBlocking { - dataStore.data.firstOrNull()?.let { preferences -> - preferences[stringPreferencesKey(key)] ?: defValue - } ?: defValue - } - } - - @Throws(IOException::class) - fun putString(key: String, value: String) { - runBlocking { - dataStore.edit { preferences -> - preferences[stringPreferencesKey(key)] = value - } - } - } - - @Throws(IOException::class) - fun getBoolean(key: String, defValue: Boolean): Boolean { - return runBlocking { - dataStore.data.firstOrNull()?.let { preferences -> - preferences[booleanPreferencesKey(key)] ?: defValue - } ?: defValue - } - } - - @Throws(IOException::class) - fun putBoolean(key: String, value: Boolean) { - runBlocking { - dataStore.edit { preferences -> - preferences[booleanPreferencesKey(key)] = value - } - } - } - - @Throws(IOException::class) - fun deletePreference(key: String) { - runBlocking { - dataStore.edit { preferences -> - preferences.remove(stringPreferencesKey(key)) - preferences.remove(intPreferencesKey(key)) - preferences.remove(booleanPreferencesKey(key)) - preferences.remove(floatPreferencesKey(key)) - preferences.remove(longPreferencesKey(key)) - preferences.remove(doublePreferencesKey(key)) - } - } - } - - - fun getIntAsync(key: String, defValue: Int): Deferred { - return CoroutineScope(Dispatchers.IO).async { - dataStore.data.firstOrNull()?.let { preferences -> - preferences[intPreferencesKey(key)] ?: defValue - } ?: defValue - } - } - - - fun putIntAsync(key: String, value: Int) { - CoroutineScope(Dispatchers.IO).launch { - dataStore.edit { preferences -> - preferences[intPreferencesKey(key)] = value - } - } - } - - - fun getStringAsync(key: String, defValue: String): Deferred { - return CoroutineScope(Dispatchers.IO).async { - dataStore.data.firstOrNull()?.let { preferences -> - preferences[stringPreferencesKey(key)] ?: defValue - } ?: defValue - } - } - - fun putStringAsync(key: String, value: String) { - CoroutineScope(Dispatchers.IO).launch { - dataStore.edit { preferences -> - preferences[stringPreferencesKey(key)] = value - } - } - } - - fun getBooleanAsync(key: String, defValue: Boolean): Deferred { - return CoroutineScope(Dispatchers.IO).async { - dataStore.data.firstOrNull()?.let { preferences -> - preferences[booleanPreferencesKey(key)] ?: defValue - } ?: defValue - } - } - - - fun putBooleanAsync(key: String, value: Boolean) { - CoroutineScope(Dispatchers.IO).launch { - dataStore.edit { preferences -> - preferences[booleanPreferencesKey(key)] = value - } - } - } - - - fun deletePreferenceAsync(key: String) { - CoroutineScope(Dispatchers.IO).launch { - dataStore.edit { preferences -> - preferences.remove(stringPreferencesKey(key)) - preferences.remove(intPreferencesKey(key)) - preferences.remove(booleanPreferencesKey(key)) - preferences.remove(floatPreferencesKey(key)) - preferences.remove(longPreferencesKey(key)) - preferences.remove(doublePreferencesKey(key)) - } - } - } -} - +/* + QQ Versions Tool for Android™ + Copyright (C) 2023 klxiaoniu + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package com.xiaoniu.qqversionlist.util + +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.core.IOException +import androidx.datastore.preferences.SharedPreferencesMigration +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.booleanPreferencesKey +import androidx.datastore.preferences.core.doublePreferencesKey +import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.floatPreferencesKey +import androidx.datastore.preferences.core.intPreferencesKey +import androidx.datastore.preferences.core.longPreferencesKey +import androidx.datastore.preferences.core.stringPreferencesKey +import androidx.datastore.preferences.preferencesDataStore +import com.xiaoniu.qqversionlist.TipTimeApplication +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking + +object DataStoreUtil { + private val Context.dataStore: DataStore by preferencesDataStore(name = "data", + produceMigrations = { context -> + listOf( + SharedPreferencesMigration(context, "data") + ) + }) + + private val dataStore: DataStore by lazy { + TipTimeApplication.instance.dataStore + } + + @Throws(IOException::class) + fun getInt(key: String, defValue: Int): Int { + return runBlocking { + dataStore.data.firstOrNull()?.let { preferences -> + preferences[intPreferencesKey(key)] ?: defValue + } ?: defValue + } + } + + @Throws(IOException::class) + fun putInt(key: String, value: Int) { + runBlocking { + dataStore.edit { preferences -> + preferences[intPreferencesKey(key)] = value + } + } + } + + @Throws(IOException::class) + fun getString(key: String, defValue: String): String { + return runBlocking { + dataStore.data.firstOrNull()?.let { preferences -> + preferences[stringPreferencesKey(key)] ?: defValue + } ?: defValue + } + } + + @Throws(IOException::class) + fun putString(key: String, value: String) { + runBlocking { + dataStore.edit { preferences -> + preferences[stringPreferencesKey(key)] = value + } + } + } + + @Throws(IOException::class) + fun getBoolean(key: String, defValue: Boolean): Boolean { + return runBlocking { + dataStore.data.firstOrNull()?.let { preferences -> + preferences[booleanPreferencesKey(key)] ?: defValue + } ?: defValue + } + } + + @Throws(IOException::class) + fun putBoolean(key: String, value: Boolean) { + runBlocking { + dataStore.edit { preferences -> + preferences[booleanPreferencesKey(key)] = value + } + } + } + + @Throws(IOException::class) + fun deletePreference(key: String) { + runBlocking { + dataStore.edit { preferences -> + preferences.remove(stringPreferencesKey(key)) + preferences.remove(intPreferencesKey(key)) + preferences.remove(booleanPreferencesKey(key)) + preferences.remove(floatPreferencesKey(key)) + preferences.remove(longPreferencesKey(key)) + preferences.remove(doublePreferencesKey(key)) + } + } + } + + + fun getIntAsync(key: String, defValue: Int): Deferred { + return CoroutineScope(Dispatchers.IO).async { + dataStore.data.firstOrNull()?.let { preferences -> + preferences[intPreferencesKey(key)] ?: defValue + } ?: defValue + } + } + + + fun putIntAsync(key: String, value: Int) { + CoroutineScope(Dispatchers.IO).launch { + dataStore.edit { preferences -> + preferences[intPreferencesKey(key)] = value + } + } + } + + + fun getStringAsync(key: String, defValue: String): Deferred { + return CoroutineScope(Dispatchers.IO).async { + dataStore.data.firstOrNull()?.let { preferences -> + preferences[stringPreferencesKey(key)] ?: defValue + } ?: defValue + } + } + + fun putStringAsync(key: String, value: String) { + CoroutineScope(Dispatchers.IO).launch { + dataStore.edit { preferences -> + preferences[stringPreferencesKey(key)] = value + } + } + } + + fun getBooleanAsync(key: String, defValue: Boolean): Deferred { + return CoroutineScope(Dispatchers.IO).async { + dataStore.data.firstOrNull()?.let { preferences -> + preferences[booleanPreferencesKey(key)] ?: defValue + } ?: defValue + } + } + + + fun putBooleanAsync(key: String, value: Boolean) { + CoroutineScope(Dispatchers.IO).launch { + dataStore.edit { preferences -> + preferences[booleanPreferencesKey(key)] = value + } + } + } + + + fun deletePreferenceAsync(key: String) { + CoroutineScope(Dispatchers.IO).launch { + dataStore.edit { preferences -> + preferences.remove(stringPreferencesKey(key)) + preferences.remove(intPreferencesKey(key)) + preferences.remove(booleanPreferencesKey(key)) + preferences.remove(floatPreferencesKey(key)) + preferences.remove(longPreferencesKey(key)) + preferences.remove(doublePreferencesKey(key)) + } + } + } +} + diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/util/Extensions.kt b/app/src/main/java/com/xiaoniu/qqversionlist/util/Extensions.kt index 6fdd930..f336d4c 100644 --- a/app/src/main/java/com/xiaoniu/qqversionlist/util/Extensions.kt +++ b/app/src/main/java/com/xiaoniu/qqversionlist/util/Extensions.kt @@ -20,5 +20,7 @@ package com.xiaoniu.qqversionlist.util import android.content.res.Resources -val Number.dp get() = (toFloat() * Resources.getSystem().displayMetrics.density).toInt() -val Number.pxToDp get() = (toFloat() / Resources.getSystem().displayMetrics.density).toInt() +object Extensions { + val Number.dp get() = (toFloat() * Resources.getSystem().displayMetrics.density).toInt() + val Number.pxToDp get() = (toFloat() / Resources.getSystem().displayMetrics.density).toInt() +} diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/util/QQVersionBeanUtil.kt b/app/src/main/java/com/xiaoniu/qqversionlist/util/QQVersionBeanUtil.kt new file mode 100644 index 0000000..4c7f9f0 --- /dev/null +++ b/app/src/main/java/com/xiaoniu/qqversionlist/util/QQVersionBeanUtil.kt @@ -0,0 +1,46 @@ +package com.xiaoniu.qqversionlist.util + +import com.xiaoniu.qqversionlist.TipTimeApplication.Companion.EARLIEST_QQNT_FRAMEWORK_VERSION_STABLE +import com.xiaoniu.qqversionlist.data.QQVersionBean +import com.xiaoniu.qqversionlist.ui.MainActivity +import kotlinx.serialization.json.Json +import org.apache.maven.artifact.versioning.DefaultArtifactVersion + +object QQVersionBeanUtil { + fun qqVersionBeanUtil(thisActivity: MainActivity, responseData: String){ + val start = (responseData.indexOf("versions64\":[")) + 12 + val end = (responseData.indexOf(";\n" + " typeof")) + val totalJson = responseData.substring(start, end) + thisActivity.qqVersion = totalJson.split("},{").reversed().map { + val pstart = it.indexOf("{\"versions") + val pend = it.indexOf(",\"length") + val json = it.substring(pstart, pend) + Json.decodeFromString(json).apply { + jsonString = json + // 标记本机 Android QQ 版本 + this.displayInstall = (DataStoreUtil.getString( + "QQVersionInstall", "" + ) == this.versionNumber) + this.isAccessibility = false + // 无障碍标记 + /*DefaultArtifactVersion(this.versionNumber) >= DefaultArtifactVersion( + EARLIEST_ACCESSIBILITY_VERSION + )*/ + + this.isQQNTFramework = + DefaultArtifactVersion(this.versionNumber) >= DefaultArtifactVersion( + EARLIEST_QQNT_FRAMEWORK_VERSION_STABLE + ) + } + } + if (DataStoreUtil.getBoolean( + "displayFirst", true + ) + ) thisActivity.qqVersion[0].displayType = 1 + // 舍弃 currentQQVersion = qqVersion.first().versionNumber + // 大版本号也放持久化存储了,否则猜版 Shortcut 因为加载过快而获取不到东西 + DataStoreUtil.putStringAsync( + "versionBig", thisActivity.qqVersion.first().versionNumber + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/xiaoniu/qqversionlist/util/TIMVersionBeanUtil.kt b/app/src/main/java/com/xiaoniu/qqversionlist/util/TIMVersionBeanUtil.kt new file mode 100644 index 0000000..4c29aa6 --- /dev/null +++ b/app/src/main/java/com/xiaoniu/qqversionlist/util/TIMVersionBeanUtil.kt @@ -0,0 +1,105 @@ +package com.xiaoniu.qqversionlist.util + +import com.google.gson.Gson +import com.google.gson.JsonObject +import com.xiaoniu.qqversionlist.data.TIMVersionBean +import com.xiaoniu.qqversionlist.ui.MainActivity + +object TIMVersionBeanUtil { + fun timVersionBeanUtil(thisActivity: MainActivity, responseData: String) { + val start = (responseData.indexOf("var params= ")) + 12 + val end = (responseData.indexOf(";\n" + " typeof")) + val jsonString = responseData.substring(start, end) + val gson = Gson() + val jsonData = gson.fromJson(jsonString, JsonObject::class.java) + + thisActivity.timVersion = mutableListOf() + + val download = jsonData.getAsJsonObject("app").getAsJsonObject("download") + val androidVersion = download.get("androidVersion").asString + val androidDatetime = download.get("androidDatetime").asString + + (thisActivity.timVersion as MutableList).add( + TIMVersionBean( + version = androidVersion, + datetime = androidDatetime, + fix = "".split("
"), + new = "", + jsonString = gson.toJson(JsonObject().apply { + addProperty("version", androidVersion) + addProperty("datetime", androidDatetime) + addProperty("fix", "") + addProperty("new", "") + }).toString() + ) + ) + + // 从 latest 项中获取 Android 版本 + val latest = jsonData.getAsJsonObject("app").getAsJsonArray("latest") + latest.forEach { item -> + val platform = item.asJsonObject.get("platform").asString + if (platform == "Android") { + val version = item.asJsonObject.get("version").asString + val datetime = item.asJsonObject.get("datetime").asString + val fix = item.asJsonObject.get("fix").asString + val newFeature = item.asJsonObject.get("new").asString + + (thisActivity.timVersion as MutableList).add( + TIMVersionBean( + version = version, + datetime = datetime, + fix = fix.split("
"), + new = newFeature, + jsonString = gson.toJson(JsonObject().apply { + addProperty("version", version) + addProperty("datetime", datetime) + addProperty("fix", fix) + addProperty("new", newFeature) + }).toString() + ) + ) + } + } + + // 从 history 项中获取 Android 版本 + val history = jsonData.getAsJsonObject("app").getAsJsonArray("history") + history.forEach { versionItem -> + val version = versionItem.asJsonObject.get("version").asString + val logs = versionItem.asJsonObject.getAsJsonArray("logs") + logs.forEach { logItem -> + val platform = logItem.asJsonObject.get("platform").asString + if (platform == "Android") { + val datetime = logItem.asJsonObject.get("datetime").asString + val fix = logItem.asJsonObject.get("fix").asString + val newFeature = logItem.asJsonObject.get("new").asString + + (thisActivity.timVersion as MutableList).add( + TIMVersionBean( + version = version, + datetime = datetime, + fix = fix.split("
"), + new = newFeature, + jsonString = gson.toJson(JsonObject().apply { + addProperty("version", version) + addProperty("datetime", datetime) + addProperty("fix", fix) + addProperty("new", newFeature) + }).toString() + ) + ) + } + } + } + + // 去除重复的版本号 + thisActivity.timVersion = thisActivity.timVersion.distinctBy { it.jsonString } + + if (DataStoreUtil.getBoolean( + "displayFirst", true + ) + ) thisActivity.timVersion[0].displayType = 1 + DataStoreUtil.putStringAsync( + "versionBig", thisActivity.timVersion.first().version + ) + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/item_version.xml b/app/src/main/res/layout/item_qq_version.xml similarity index 98% rename from app/src/main/res/layout/item_version.xml rename to app/src/main/res/layout/item_qq_version.xml index e7b4553..26318be 100644 --- a/app/src/main/res/layout/item_version.xml +++ b/app/src/main/res/layout/item_qq_version.xml @@ -1,210 +1,210 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_version_detail.xml b/app/src/main/res/layout/item_qq_version_detail.xml similarity index 100% rename from app/src/main/res/layout/item_version_detail.xml rename to app/src/main/res/layout/item_qq_version_detail.xml diff --git a/app/src/main/res/values-night-v27/themes.xml b/app/src/main/res/values-night-v27/themes.xml index 16e0e6b..c321cb3 100644 --- a/app/src/main/res/values-night-v27/themes.xml +++ b/app/src/main/res/values-night-v27/themes.xml @@ -18,7 +18,7 @@ -