main d44c471fb38f cached
275 files
1.1 MB
258.2k tokens
1 requests
Download .txt
Showing preview only (1,278K chars total). Download the full file or copy to clipboard to get everything.
Repository: bggRGjQaUbCoE/c001apk-compose
Branch: main
Commit: d44c471fb38f
Files: 275
Total size: 1.1 MB

Directory structure:
gitextract_r5thwsnn/

├── .gitignore
├── LICENSE
├── README.md
├── app/
│   ├── .gitignore
│   ├── build.gradle.kts
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── example/
│       │               └── c001apk/
│       │                   └── compose/
│       │                       └── ExampleInstrumentedTest.kt
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── assets/
│       │   │   └── devicemodel.txt
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── example/
│       │   │           └── c001apk/
│       │   │               └── compose/
│       │   │                   ├── C001Application.kt
│       │   │                   ├── constant/
│       │   │                   │   └── Constants.kt
│       │   │                   ├── di/
│       │   │                   │   ├── DataStoreModule.kt
│       │   │                   │   ├── DatabaseModule.kt
│       │   │                   │   └── NetworkModule.kt
│       │   │                   ├── logic/
│       │   │                   │   ├── dao/
│       │   │                   │   │   ├── HistoryFavoriteDao.kt
│       │   │                   │   │   ├── HomeMenuDao.kt
│       │   │                   │   │   ├── RecentAtUserDao.kt
│       │   │                   │   │   └── StringEntityDao.kt
│       │   │                   │   ├── database/
│       │   │                   │   │   ├── HistoryFavoriteDatabase.kt
│       │   │                   │   │   ├── HomeMenuDatabase.kt
│       │   │                   │   │   ├── RecentAtUserDatabase.kt
│       │   │                   │   │   └── StringEntityDatabase.kt
│       │   │                   │   ├── datastore/
│       │   │                   │   │   ├── UserPreferencesCompat.kt
│       │   │                   │   │   ├── UserPreferencesDataSource.kt
│       │   │                   │   │   └── UserPreferencesSerializer.kt
│       │   │                   │   ├── model/
│       │   │                   │   │   ├── AppItem.kt
│       │   │                   │   │   ├── CheckCountResponse.kt
│       │   │                   │   │   ├── CheckResponse.kt
│       │   │                   │   │   ├── CreateFeedResponse.kt
│       │   │                   │   │   ├── DeviceInfo.kt
│       │   │                   │   │   ├── FeedAdapter.kt
│       │   │                   │   │   ├── FeedArticleContentBean.kt
│       │   │                   │   │   ├── FeedContentResponse.kt
│       │   │                   │   │   ├── FeedEntity.kt
│       │   │                   │   │   ├── HomeFeedResponse.kt
│       │   │                   │   │   ├── HomeMenu.kt
│       │   │                   │   │   ├── LikeAdapter.kt
│       │   │                   │   │   ├── LikeResponse.kt
│       │   │                   │   │   ├── LoadUrlResponse.kt
│       │   │                   │   │   ├── LoginResponse.kt
│       │   │                   │   │   ├── MessageListResponse.kt
│       │   │                   │   │   ├── OSSUploadPrepareModel.kt
│       │   │                   │   │   ├── OSSUploadPrepareResponse.kt
│       │   │                   │   │   ├── PostReplyResponse.kt
│       │   │                   │   │   ├── RecentAtUser.kt
│       │   │                   │   │   ├── StringEntity.kt
│       │   │                   │   │   ├── TopicBean.kt
│       │   │                   │   │   ├── TotalReplyResponse.kt
│       │   │                   │   │   ├── UpdateCheckItem.kt
│       │   │                   │   │   └── UpdateCheckResponse.kt
│       │   │                   │   ├── network/
│       │   │                   │   │   └── ApiService.kt
│       │   │                   │   ├── providable/
│       │   │                   │   │   └── LocalUserPreferences.kt
│       │   │                   │   ├── repository/
│       │   │                   │   │   ├── BlackListRepo.kt
│       │   │                   │   │   ├── HistoryFavoriteRepo.kt
│       │   │                   │   │   ├── HomeMenuRepo.kt
│       │   │                   │   │   ├── NetworkRepo.kt
│       │   │                   │   │   ├── RecentAtUserRepo.kt
│       │   │                   │   │   ├── RecentEmojiRepo.kt
│       │   │                   │   │   ├── SearchHistoryRepo.kt
│       │   │                   │   │   └── UserPreferencesRepository.kt
│       │   │                   │   └── state/
│       │   │                   │       ├── FooterState.kt
│       │   │                   │       ├── LoadingState.kt
│       │   │                   │       └── State.kt
│       │   │                   ├── ui/
│       │   │                   │   ├── app/
│       │   │                   │   │   ├── AppContentScreen.kt
│       │   │                   │   │   ├── AppContentViewModel.kt
│       │   │                   │   │   ├── AppScreen.kt
│       │   │                   │   │   └── AppViewModel.kt
│       │   │                   │   ├── appupdate/
│       │   │                   │   │   └── AppUpdateScreen.kt
│       │   │                   │   ├── base/
│       │   │                   │   │   ├── BaseViewModel.kt
│       │   │                   │   │   └── PrefsViewModel.kt
│       │   │                   │   ├── blacklist/
│       │   │                   │   │   ├── BlackListScreen.kt
│       │   │                   │   │   └── BlackListViewModel.kt
│       │   │                   │   ├── carousel/
│       │   │                   │   │   ├── CarouselContentScreen.kt
│       │   │                   │   │   ├── CarouselScreen.kt
│       │   │                   │   │   └── CarouselViewModel.kt
│       │   │                   │   ├── chat/
│       │   │                   │   │   ├── ChatScreen.kt
│       │   │                   │   │   └── ChatViewModel.kt
│       │   │                   │   ├── collection/
│       │   │                   │   │   ├── CollectionScreen.kt
│       │   │                   │   │   └── CollectionViewModel.kt
│       │   │                   │   ├── component/
│       │   │                   │   │   ├── ArticleItem.kt
│       │   │                   │   │   ├── Button.kt
│       │   │                   │   │   ├── ChatEditText.kt
│       │   │                   │   │   ├── CoilLoader.kt
│       │   │                   │   │   ├── CommonScreen.kt
│       │   │                   │   │   ├── FooterCard.kt
│       │   │                   │   │   ├── IconText.kt
│       │   │                   │   │   ├── ImageView.kt
│       │   │                   │   │   ├── ItemCard.kt
│       │   │                   │   │   ├── LinkText.kt
│       │   │                   │   │   ├── NineImageView.kt
│       │   │                   │   │   ├── Transitions.kt
│       │   │                   │   │   ├── WebView.kt
│       │   │                   │   │   ├── cards/
│       │   │                   │   │   │   ├── AppCard.kt
│       │   │                   │   │   │   ├── AppInfoCard.kt
│       │   │                   │   │   │   ├── AppUpdateCard.kt
│       │   │                   │   │   │   ├── CardIndicator.kt
│       │   │                   │   │   │   ├── CarouselCard.kt
│       │   │                   │   │   │   ├── ChatLeftCard.kt
│       │   │                   │   │   │   ├── ChatRightCard.kt
│       │   │                   │   │   │   ├── ChatTimeCard.kt
│       │   │                   │   │   │   ├── CollectionCard.kt
│       │   │                   │   │   │   ├── FeedArticleCard.kt
│       │   │                   │   │   │   ├── FeedCard.kt
│       │   │                   │   │   │   ├── FeedReplyCard.kt
│       │   │                   │   │   │   ├── FeedReplySortCard.kt
│       │   │                   │   │   │   ├── HistoryCard.kt
│       │   │                   │   │   │   ├── IconLinkGridCard.kt
│       │   │                   │   │   │   ├── IconMiniGridCard.kt
│       │   │                   │   │   │   ├── IconMiniScrollCard.kt
│       │   │                   │   │   │   ├── IconScrollCard.kt
│       │   │                   │   │   │   ├── ImageSquareScrollCard.kt
│       │   │                   │   │   │   ├── ImageTextScrollCard.kt
│       │   │                   │   │   │   ├── LoadingCard.kt
│       │   │                   │   │   │   ├── MessageCard.kt
│       │   │                   │   │   │   ├── MessageFFFCard.kt
│       │   │                   │   │   │   ├── MessageHeaderCard.kt
│       │   │                   │   │   │   ├── MessageListCard.kt
│       │   │                   │   │   │   ├── MessageWidgetCard.kt
│       │   │                   │   │   │   ├── NotificationCard.kt
│       │   │                   │   │   │   ├── SearchHistoryCard.kt
│       │   │                   │   │   │   ├── TextCard.kt
│       │   │                   │   │   │   ├── TitleCard.kt
│       │   │                   │   │   │   └── UserInfoCard.kt
│       │   │                   │   │   ├── icons/
│       │   │                   │   │   │   └── Swatch.kt
│       │   │                   │   │   └── settings/
│       │   │                   │   │       ├── BasicListItem.kt
│       │   │                   │   │       ├── DropdownListItem.kt
│       │   │                   │   │       ├── StateBasicListItem.kt
│       │   │                   │   │       ├── StateDropdownListItem.kt
│       │   │                   │   │       └── SwitchListItem.kt
│       │   │                   │   ├── coolpic/
│       │   │                   │   │   ├── CoolPicContentScreen.kt
│       │   │                   │   │   ├── CoolPicContentViewModel.kt
│       │   │                   │   │   └── CoolPicScreen.kt
│       │   │                   │   ├── dyh/
│       │   │                   │   │   ├── DyhContentScreen.kt
│       │   │                   │   │   ├── DyhContentViewModel.kt
│       │   │                   │   │   └── DyhScreen.kt
│       │   │                   │   ├── feed/
│       │   │                   │   │   ├── FeedScreen.kt
│       │   │                   │   │   ├── FeedViewModel.kt
│       │   │                   │   │   └── reply/
│       │   │                   │   │       ├── ReplyActivity.kt
│       │   │                   │   │       ├── ReplyViewModel.kt
│       │   │                   │   │       └── emoji/
│       │   │                   │   │           ├── EmojiChildPagerAdapter.kt
│       │   │                   │   │           ├── EmojiGridAdapter.kt
│       │   │                   │   │           └── EmojiPagerAdapter.kt
│       │   │                   │   ├── ffflist/
│       │   │                   │   │   ├── FFFContentScreen.kt
│       │   │                   │   │   ├── FFFContentViewModel.kt
│       │   │                   │   │   └── FFFListScreen.kt
│       │   │                   │   ├── history/
│       │   │                   │   │   ├── HistoryScreen.kt
│       │   │                   │   │   └── HistoryViewModel.kt
│       │   │                   │   ├── home/
│       │   │                   │   │   ├── HomeScreen.kt
│       │   │                   │   │   ├── app/
│       │   │                   │   │   │   ├── AppListScreen.kt
│       │   │                   │   │   │   └── AppListViewModel.kt
│       │   │                   │   │   ├── feed/
│       │   │                   │   │   │   ├── HomeFeedScreen.kt
│       │   │                   │   │   │   └── HomeFeedViewModel.kt
│       │   │                   │   │   └── topic/
│       │   │                   │   │       ├── HomeTopicScreen.kt
│       │   │                   │   │       └── HomeTopicViewModel.kt
│       │   │                   │   ├── login/
│       │   │                   │   │   ├── LoginScreen.kt
│       │   │                   │   │   └── LoginViewModel.kt
│       │   │                   │   ├── main/
│       │   │                   │   │   ├── MainActivity.kt
│       │   │                   │   │   ├── MainNavigation.kt
│       │   │                   │   │   ├── MainScreen.kt
│       │   │                   │   │   ├── MainViewModel.kt
│       │   │                   │   │   └── Router.kt
│       │   │                   │   ├── message/
│       │   │                   │   │   ├── MessageScreen.kt
│       │   │                   │   │   └── MessageViewModel.kt
│       │   │                   │   ├── notification/
│       │   │                   │   │   ├── NoticeScreen.kt
│       │   │                   │   │   └── NoticeViewModel.kt
│       │   │                   │   ├── others/
│       │   │                   │   │   └── CopyTextScreen.kt
│       │   │                   │   ├── search/
│       │   │                   │   │   ├── SearchContentScreen.kt
│       │   │                   │   │   ├── SearchContentViewModel.kt
│       │   │                   │   │   ├── SearchResultScreen.kt
│       │   │                   │   │   ├── SearchScreen.kt
│       │   │                   │   │   └── SearchViewModel.kt
│       │   │                   │   ├── settings/
│       │   │                   │   │   ├── AboutScreen.kt
│       │   │                   │   │   ├── LicenseScreen.kt
│       │   │                   │   │   ├── ParamsScreen.kt
│       │   │                   │   │   ├── SettingsScreen.kt
│       │   │                   │   │   └── SettingsViewModel.kt
│       │   │                   │   ├── theme/
│       │   │                   │   │   ├── Color.kt
│       │   │                   │   │   ├── Theme.kt
│       │   │                   │   │   └── Type.kt
│       │   │                   │   ├── topic/
│       │   │                   │   │   ├── TopicContentScreen.kt
│       │   │                   │   │   ├── TopicContentViewModel.kt
│       │   │                   │   │   ├── TopicScreen.kt
│       │   │                   │   │   └── TopicViewModel.kt
│       │   │                   │   ├── user/
│       │   │                   │   │   ├── UserScreen.kt
│       │   │                   │   │   └── UserViewModel.kt
│       │   │                   │   └── webview/
│       │   │                   │       ├── WebViewScreen.kt
│       │   │                   │       └── WebViewViewModel.kt
│       │   │                   ├── util/
│       │   │                   │   ├── AddCookiesInterceptor.kt
│       │   │                   │   ├── Base64Utils.kt
│       │   │                   │   ├── CacheDataManager.kt
│       │   │                   │   ├── CommentHelper.kt
│       │   │                   │   ├── CookieUtil.kt
│       │   │                   │   ├── DateUtils.kt
│       │   │                   │   ├── EmojiUtils.kt
│       │   │                   │   ├── Extensions.kt
│       │   │                   │   ├── ImageDownloadUtil.kt
│       │   │                   │   ├── ImageShowUtil.kt
│       │   │                   │   ├── LoginCookiesInterceptor.kt
│       │   │                   │   ├── NetWorkUtil.kt
│       │   │                   │   ├── OSSUtil.kt
│       │   │                   │   ├── OssUploadUtil.kt
│       │   │                   │   ├── SpannableStringBuilderUtil.kt
│       │   │                   │   ├── TokenDeviceUtils.kt
│       │   │                   │   └── Utils.kt
│       │   │                   └── view/
│       │   │                       ├── BadgeDrawable.kt
│       │   │                       ├── BadgedImageView.kt
│       │   │                       ├── CenteredImageSpan.kt
│       │   │                       ├── CircleIndexIndicator.kt
│       │   │                       ├── CircleIndicator.kt
│       │   │                       ├── LinkTextView.kt
│       │   │                       ├── MyURLSpan.kt
│       │   │                       ├── NestedScrollableHost.kt
│       │   │                       ├── NineGridImageView.kt
│       │   │                       ├── RoundedImageView.kt
│       │   │                       ├── SmoothInputLayout.kt
│       │   │                       └── circleindicator/
│       │   │                           ├── BaseCircleIndicator.kt
│       │   │                           ├── CircleIndicator3.kt
│       │   │                           └── Config.kt
│       │   ├── proto/
│       │   │   └── UserPreferences.proto
│       │   └── res/
│       │       ├── anim/
│       │       │   ├── anim_bottom_sheet_slide_down.xml
│       │       │   ├── anim_bottom_sheet_slide_up.xml
│       │       │   ├── indicator_animator.xml
│       │       │   ├── indicator_animator_reverse.xml
│       │       │   └── scale_with_alpha.xml
│       │       ├── color/
│       │       │   └── image_stroke.xml
│       │       ├── drawable/
│       │       │   ├── ic_author.xml
│       │       │   ├── ic_feed_top.xml
│       │       │   ├── ic_launcher_foreground.xml
│       │       │   ├── ic_photo.xml
│       │       │   ├── ic_subauthor.xml
│       │       │   ├── outline_alternate_email_24.xml
│       │       │   ├── outline_backspace_24.xml
│       │       │   ├── outline_emoji_emotions_24.xml
│       │       │   ├── outline_image_24.xml
│       │       │   ├── outline_keyboard_hide_24.xml
│       │       │   ├── outline_keyboard_show_24.xml
│       │       │   ├── outline_note_alt_24.xml
│       │       │   ├── outline_tag_24.xml
│       │       │   ├── round_corners_12.xml
│       │       │   ├── selector_bg_12_trans.xml
│       │       │   ├── selector_bg_trans.xml
│       │       │   ├── selector_emoji.xml
│       │       │   ├── selector_emoji_indicator.xml
│       │       │   ├── selector_emoji_indicator_selected.xml
│       │       │   ├── selector_reply.xml
│       │       │   ├── shape_oval_primary.xml
│       │       │   └── white_radius.xml
│       │       ├── layout/
│       │       │   ├── activity_reply.xml
│       │       │   ├── dialog_refresh.xml
│       │       │   ├── item_captcha.xml
│       │       │   ├── item_emoji.xml
│       │       │   └── item_emoji_child_viewpager.xml
│       │       ├── layout-land/
│       │       │   └── activity_reply.xml
│       │       ├── mipmap-anydpi-v26/
│       │       │   ├── ic_launcher.xml
│       │       │   └── ic_launcher_round.xml
│       │       ├── values/
│       │       │   ├── attrs.xml
│       │       │   ├── colors.xml
│       │       │   ├── strings.xml
│       │       │   └── themes.xml
│       │       ├── values-night/
│       │       │   └── colors.xml
│       │       ├── values-night-v31/
│       │       │   └── colors.xml
│       │       ├── values-v31/
│       │       │   └── colors.xml
│       │       └── xml/
│       │           ├── backup_rules.xml
│       │           ├── data_extraction_rules.xml
│       │           └── file_provider_paths.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── example/
│                       └── c001apk/
│                           └── compose/
│                               └── ExampleUnitTest.kt
├── build.gradle.kts
├── gradle/
│   ├── libs.versions.toml
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── renovate.json
└── settings.gradle.kts

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
*.log
.idea
.kotlin
/coilimageloader
/mojito
/SketchImageViewLoader


================================================
FILE: LICENSE
================================================
                    GNU AFFERO GENERAL PUBLIC LICENSE
                       Version 3, 19 November 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.

  A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate.  Many developers of free software are heartened and
encouraged by the resulting cooperation.  However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.

  The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community.  It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server.  Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.

  An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals.  This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU Affero General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Remote Network Interaction; Use with the GNU General Public License.

  Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software.  This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time.  Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    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 <https://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source.  For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code.  There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.


================================================
FILE: README.md
================================================
# c001apk-compose

test only


================================================
FILE: app/.gitignore
================================================
/build
/release
/schemas

================================================
FILE: app/build.gradle.kts
================================================
import com.android.build.gradle.internal.api.ApkVariantOutputImpl
import org.jetbrains.kotlin.konan.properties.Properties
import java.io.ByteArrayOutputStream

plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.google.dagger.hilt.android)
    alias(libs.plugins.google.devtools.ksp)
    alias(libs.plugins.google.protobuf)
    alias(libs.plugins.jetbrains.kotlin.android)
    alias(libs.plugins.jetbrains.kotlin.plugin.compose)
    alias(libs.plugins.kotlin.parcelize)
}

fun String.execute(currentWorkingDir: File = file("./")): String {
    val byteOut = ByteArrayOutputStream()
    rootProject.exec {
        workingDir = currentWorkingDir
        commandLine = split("\\s".toRegex())
        standardOutput = byteOut
    }
    return String(byteOut.toByteArray()).trim()
}

val gitCommitCount = "git rev-list HEAD --count".execute().toInt()
val gitCommitHash = "git rev-parse --verify --short HEAD".execute()

android {
    namespace = "com.example.c001apk.compose"
    compileSdk = 35

    defaultConfig {
        applicationId = "com.example.c001apk.compose"
        minSdk = 24
        targetSdk = 35
        versionCode = gitCommitCount
        versionName = gitCommitHash

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

        vectorDrawables {
            useSupportLibrary = true
        }
    }

    val localProperties = Properties().also {
        val properties = rootProject.file("local.properties")
        if (properties.exists())
            it.load(properties.inputStream())
    }

    val config = localProperties.getProperty("KEYSTORE_PATH")?.let {
        signingConfigs.create("release") {
            storeFile = file(it)
            storePassword = localProperties.getProperty("KEYSTORE_PASSWORD")
            keyAlias = localProperties.getProperty("KEY_ALIAS")
            keyPassword = localProperties.getProperty("KEY_PASSWORD")
            enableV2Signing = true
            enableV3Signing = true
        }
    }

    buildTypes {
        all {
            signingConfig = config ?: signingConfigs["debug"]
        }
        release {
            isMinifyEnabled = true
            isShrinkResources = true
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }

    kotlinOptions {
        jvmTarget = "17"
    }

    buildFeatures {
        compose = true
        viewBinding = true
        buildConfig = true
    }

    composeOptions {
        kotlinCompilerExtensionVersion = "1.5.15"
    }

    packagingOptions.resources.excludes += setOf(
        "META-INF/**",
        "okhttp3/**",
        "kotlin/**",
        "org/**",
        "**.properties",
        "**.bin",
        "**/*.proto"
    )

    dependenciesInfo.includeInApk = false

    applicationVariants.configureEach {
        outputs.configureEach {
            if (baseName == "release")
                (this as? ApkVariantOutputImpl)?.outputFileName =
                    "c001apk-compose_$versionName($versionCode).apk"
        }
    }
}

ksp {
    arg("room.incremental", "true")
    arg("room.expandProjection", "true")
    arg("room.schemaLocation", "$projectDir/schemas")
}

protobuf {
    protoc {
        artifact = libs.google.protobuf.protoc.get().toString()
    }

    generateProtoTasks {
        all().forEach { task ->
            task.builtins {
                register("java") {
                    option("lite")
                }
            }
        }
    }
}

dependencies {

    androidTestImplementation(libs.androidx.junit)
    androidTestImplementation(libs.androidx.espresso.core)
    androidTestImplementation(platform(libs.androidx.compose.bom))
    androidTestImplementation(libs.androidx.ui.test.junit4)
    debugImplementation(libs.androidx.ui.tooling)
    debugImplementation(libs.androidx.ui.test.manifest)
    debugImplementation(libs.leakcanary.android)
    testImplementation(libs.junit)

    implementation(libs.androidx.activity.compose)
    implementation(libs.androidx.appcompat)
    implementation(libs.androidx.compose.material.icons.extended)
    implementation(libs.androidx.compose.navigation)
    implementation(libs.androidx.constraintlayout.compose)
    implementation(libs.androidx.core.ktx)
    implementation(libs.androidx.datastore.core)
    implementation(libs.androidx.exifinterface)
    implementation(libs.androidx.hilt.navigation.compose)
    implementation(libs.androidx.lifecycle.livedata.ktx)
    implementation(libs.androidx.lifecycle.runtime.compose)
    implementation(libs.androidx.lifecycle.runtime.ktx)
    implementation(libs.androidx.lifecycle.viewModel.compose)
    implementation(libs.androidx.material3)
    implementation(libs.androidx.material3.window.size.android)
    implementation(libs.androidx.room.ktx)
    ksp(libs.androidx.room.compiler)
    implementation(libs.androidx.room.runtime)
    implementation(libs.androidx.ui)
    implementation(libs.androidx.ui.graphics)
    implementation(libs.androidx.ui.tooling.preview)
    implementation(platform(libs.androidx.compose.bom))
    implementation(libs.androidx.webkit)
    implementation(libs.androidx.material3.adaptive.navigation.suite)

    implementation(libs.google.accompanist.drawablepainter)
    implementation(libs.google.android.material)
    implementation(libs.google.dagger.hilt.android)
    ksp(libs.google.dagger.hilt.android.compiler)
    implementation(libs.google.protobuf.kotlin.lite)

    implementation(libs.squareup.okhttp3.logging.interceptor)
    implementation(libs.squareup.retrofit)
    implementation(libs.squareup.retrofit.converter.gson)

    implementation(libs.coil.compose)
    implementation(libs.coil.gif)
    implementation(libs.jp.wasabeef.transformers.coil)
    implementation(libs.me.zhanghai.android.appiconloader.coil)

    implementation(libs.jbcrypt)
    implementation(libs.jsoup)
    implementation(libs.toolbar.compose)
    implementation(libs.oss.android.sdk)
    implementation(libs.material.kolor)

    implementation(project(":mojito"))
    implementation(project(":SketchImageViewLoader"))
    implementation(project(":coilimageLoader"))

}

================================================
FILE: app/proguard-rules.pro
================================================
-optimizationpasses 5

# Keep DataStore fields
-keepclassmembers class * extends com.google.protobuf.GeneratedMessageLite* {
   <fields>;
}

-dontusemixedcaseclassnames
-verbose

# Preserve some attributes that may be required for reflection.
-keepattributes *Annotation*,Signature,InnerClasses,EnclosingMethod

# -keep class * extends androidx.fragment.app.Fragment{}

# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
-keepclasseswithmembernames class * {
    native <methods>;
}

# Keep setters in Views so that animations can still work.
# -keepclassmembers public class * extends android.view.View {
#     void set*(***);
#     *** get*();
# }

# We want to keep methods in Activity that could be used in the XML attribute onClick.
# -keepclassmembers class * extends android.app.Activity {
#     public void *(android.view.View);
# }

# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

-keepclassmembers class * implements android.os.Parcelable {
    public static final android.os.Parcelable$Creator CREATOR;
}

-keepclassmembers class **.R$* {
    public static <fields>;
}

# Preserve annotated Javascript interface methods.
-keepclassmembers class * {
    @android.webkit.JavascriptInterface <methods>;
}

# The support libraries contains references to newer platform versions.
# Don't warn about those in case this app is linking against an older
# platform version. We know about them, and they are safe.
-dontnote android.support.**
-dontwarn android.support.**

-dontwarn javax.annotation.**

# Understand the @Keep support annotation.
-keep class androidx.annotation.Keep
-keep @androidx.annotation.Keep class * {*;}

-keepclasseswithmembers class * {
    @androidx.annotation.Keep <methods>;
}

-keepclasseswithmembers class * {
    @androidx.annotation.Keep <fields>;
}

-keepclasseswithmembers class * {
    @androidx.annotation.Keep <init>(...);
}

-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
    static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
    static void checkExpressionValueIsNotNull(java.lang.Object, java.lang.String);
    static void checkNotNullExpressionValue(java.lang.Object, java.lang.String);
    static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String, java.lang.String);
    static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String);
    static void checkFieldIsNotNull(java.lang.Object, java.lang.String, java.lang.String);
    static void checkFieldIsNotNull(java.lang.Object, java.lang.String);
    static void checkNotNull(java.lang.Object, java.lang.String);
    static void checkNotNullParameter(java.lang.Object, java.lang.String);
}

-dontwarn org.xmlpull.v1.XmlPullParser
-dontwarn org.xmlpull.v1.XmlSerializer
-keep class org.xmlpull.v1.* {*;}

## Android architecture components: Lifecycle
# LifecycleObserver's empty constructor is considered to be unused by proguard
-keepclassmembers class * implements androidx.lifecycle.LifecycleObserver {
    <init>(...);
}
# ViewModel's empty constructor is considered to be unused by proguard
-keepclassmembers class * extends androidx.lifecycle.ViewModel {
    <init>(...);
}
# keep methods annotated with @OnLifecycleEvent even if they seem to be unused
# (Mostly for LiveData.LifecycleBoundObserver.onStateChange(), but who knows)
-keepclassmembers class * {
    @androidx.lifecycle.OnLifecycleEvent *;
}

# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature,InnerClasses
-keepattributes SourceFile,LineNumberTable
-renamesourcefileattribute SourceFile

# R8 full mode
# Once
#-keep,allowobfuscation,allowshrinking class jonathanfinerty.once.PersistedMap

# TODO: Waiting for new retrofit release to remove these rules
-keep,allowobfuscation,allowshrinking interface retrofit2.Call
-keep,allowobfuscation,allowshrinking class retrofit2.Response
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation

# org.apache.commons:commons-compress
-keep,allowoptimization class org.apache.commons.compress.archivers.zip.**

# Retrofit
-dontnote retrofit2.Platform
-keepattributes Signature
-keepattributes Exceptions

# okhttp
-dontwarn okio.**

##---------------Begin: proguard configuration for Gson  ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature

# For using GSON @Expose annotation
-keepattributes *Annotation*

# Gson specific classes
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }

# Application classes that will be serialized/deserialized over Gson
-keep class com.example.c001apk.compose.logic.model.** { <fields>; }

# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * extends com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer

# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
  @com.google.gson.annotations.SerializedName <fields>;
}

# Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken

##---------------End: proguard configuration for Gson  ----------

# Retrofit
-dontwarn retrofit2.**
-dontwarn org.codehaus.mojo.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-keepattributes *Annotation*
-keepattributes RuntimeVisibleAnnotations
-keepattributes RuntimeInvisibleAnnotations
-keepattributes RuntimeVisibleParameterAnnotations
-keepattributes RuntimeInvisibleParameterAnnotations
-keepattributes EnclosingMethod
-keepclasseswithmembers class * {
@retrofit2.* <methods>;
}
-keepclasseswithmembers interface * {
@retrofit2.* <methods>;
}

-keep class com.alibaba.sdk.android.oss.** { *; }
-dontwarn okio.**
-dontwarn org.apache.commons.codec.binary.**


================================================
FILE: app/src/androidTest/java/com/example/c001apk/compose/ExampleInstrumentedTest.kt
================================================
package com.example.c001apk.compose

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith

/**
 * Instrumented test, which will execute on an Android device.
 *
 * See [testing documentation](http://d.android.com/tools/testing).
 */
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
    @Test
    fun useAppContext() {
        // Context of the app under test.
        val appContext = InstrumentationRegistry.getInstrumentation().targetContext
        assertEquals("com.example.c001apk.compose", appContext.packageName)
    }
}

================================================
FILE: app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission
        android:name="android.permission.QUERY_ALL_PACKAGES"
        tools:ignore="QueryAllPackagesPermission" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

    <application
        android:name=".C001Application"
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:enableOnBackInvokedCallback="true"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.C001apkCompose"
        android:usesCleartextTraffic="true"
        tools:targetApi="31">

        <activity
            android:name=".ui.feed.reply.ReplyActivity"
            android:exported="false"
            android:launchMode="singleTop"
            android:theme="@style/AppThemeTranslucent"
            android:windowSoftInputMode="adjustResize" />

        <activity
            android:name=".ui.main.MainActivity"
            android:alwaysRetainTaskState="true"
            android:exported="true"
            android:label="@string/app_name"
            android:launchMode="singleTask"
            android:theme="@style/Theme.C001apkCompose"
            android:windowSoftInputMode="adjustResize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <intent-filter>
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data
                    android:host="live"
                    android:pathPattern="/.*"
                    android:scheme="coolmarket" />
                <data
                    android:host="u"
                    android:pathPattern="/.*"
                    android:scheme="coolmarket" />
                <data
                    android:host="feed"
                    android:pathPattern="/.*"
                    android:scheme="coolmarket" />
                <data
                    android:host="collection"
                    android:pathPattern="/.*"
                    android:scheme="coolmarket" />
                <data
                    android:host="apk"
                    android:pathPattern="/.*\\..*"
                    android:scheme="coolmarket" />
                <data
                    android:pathPattern="/.*"
                    android:scheme="coolmarket" />
                <data
                    android:host="com.coolapk.market"
                    android:pathPattern="/.*"
                    android:scheme="coolmarket" />
                <data
                    android:host="www.coolapk.com"
                    android:pathPattern="/.*"
                    android:scheme="coolmarket" />
                <data
                    android:host="coolapk.com"
                    android:pathPattern="/"
                    android:scheme="http" />
                <data
                    android:host="coolapk.com"
                    android:pathPattern="/apk/.*\\..*"
                    android:scheme="http" />
                <data
                    android:host="coolapk.com"
                    android:pathPattern="/game/.*\\..*"
                    android:scheme="http" />
                <data
                    android:host="coolapk.com"
                    android:pathPattern="/feed/.*"
                    android:scheme="http" />
                <data
                    android:host="coolapk.com"
                    android:pathPattern="/web/.*"
                    android:scheme="http" />
                <data
                    android:host="coolapk.com"
                    android:pathPattern="/faxian/.*"
                    android:scheme="http" />
                <data
                    android:host="coolapk.com"
                    android:pathPattern="/t/.*"
                    android:scheme="http" />
                <data
                    android:host="coolapk.com"
                    android:pathPattern="/u/.*"
                    android:scheme="http" />
                <data
                    android:host="coolapk.com"
                    android:pathPattern="/n/.*"
                    android:scheme="http" />
                <data
                    android:host="coolapk.com"
                    android:pathPattern="/album/.*"
                    android:scheme="http" />
                <data
                    android:host="www.coolapk.com"
                    android:pathPattern="/"
                    android:scheme="http" />
                <data
                    android:host="www.coolapk.com"
                    android:pathPattern="/apk/.*\\..*"
                    android:scheme="http" />
                <data
                    android:host="www.coolapk.com"
                    android:pathPattern="/game/.*\\..*"
                    android:scheme="http" />
                <data
                    android:host="www.coolapk.com"
                    android:pathPattern="/feed/.*"
                    android:scheme="http" />
                <data
                    android:host="www.coolapk.com"
                    android:pathPattern="/web/.*"
                    android:scheme="http" />
                <data
                    android:host="www.coolapk.com"
                    android:pathPattern="/faxian/.*"
                    android:scheme="http" />
                <data
                    android:host="www.coolapk.com"
                    android:pathPattern="/t/.*"
                    android:scheme="http" />
                <data
                    android:host="www.coolapk.com"
                    android:pathPattern="/u/.*"
                    android:scheme="http" />
                <data
                    android:host="www.coolapk.com"
                    android:pathPattern="/n/.*"
                    android:scheme="http" />
                <data
                    android:host="www.coolapk.com"
                    android:pathPattern="/album/.*"
                    android:scheme="https" />
                <data
                    android:host="coolapk.com"
                    android:pathPattern="/"
                    android:scheme="https" />
                <data
                    android:host="coolapk.com"
                    android:pathPattern="/apk/.*\\..*"
                    android:scheme="https" />
                <data
                    android:host="coolapk.com"
                    android:pathPattern="/game/.*\\..*"
                    android:scheme="https" />
                <data
                    android:host="coolapk.com"
                    android:pathPattern="/feed/.*"
                    android:scheme="https" />
                <data
                    android:host="coolapk.com"
                    android:pathPattern="/web/.*"
                    android:scheme="https" />
                <data
                    android:host="coolapk.com"
                    android:pathPattern="/faxian/.*"
                    android:scheme="https" />
                <data
                    android:host="coolapk.com"
                    android:pathPattern="/t/.*"
                    android:scheme="https" />
                <data
                    android:host="coolapk.com"
                    android:pathPattern="/u/.*"
                    android:scheme="https" />
                <data
                    android:host="coolapk.com"
                    android:pathPattern="/n/.*"
                    android:scheme="https" />
                <data
                    android:host="coolapk.com"
                    android:pathPattern="/album/.*"
                    android:scheme="https" />
                <data
                    android:host="www.coolapk.com"
                    android:pathPattern="/"
                    android:scheme="https" />
                <data
                    android:host="www.coolapk.com"
                    android:pathPattern="/apk/.*\\..*"
                    android:scheme="https" />
                <data
                    android:host="www.coolapk.com"
                    android:pathPattern="/game/.*\\..*"
                    android:scheme="https" />
                <data
                    android:host="www.coolapk.com"
                    android:pathPattern="/feed/.*"
                    android:scheme="https" />
                <data
                    android:host="www.coolapk.com"
                    android:pathPattern="/web/.*"
                    android:scheme="https" />
                <data
                    android:host="www.coolapk.com"
                    android:pathPattern="/faxian/.*"
                    android:scheme="https" />
                <data
                    android:host="www.coolapk.com"
                    android:pathPattern="/t/.*"
                    android:scheme="https" />
                <data
                    android:host="www.coolapk.com"
                    android:pathPattern="/u/.*"
                    android:scheme="https" />
                <data
                    android:host="www.coolapk.com"
                    android:pathPattern="/n/.*"
                    android:scheme="https" />
                <data
                    android:host="www.coolapk.com"
                    android:pathPattern="/album/.*"
                    android:scheme="https" />
                <data
                    android:host="www.coolapk1s.com"
                    android:pathPattern="/.*"
                    android:scheme="coolmarket" />
                <data
                    android:host="coolapk1s.com"
                    android:pathPattern="/"
                    android:scheme="http" />
                <data
                    android:host="coolapk1s.com"
                    android:pathPattern="/apk/.*\\..*"
                    android:scheme="http" />
                <data
                    android:host="coolapk1s.com"
                    android:pathPattern="/game/.*\\..*"
                    android:scheme="http" />
                <data
                    android:host="coolapk1s.com"
                    android:pathPattern="/feed/.*"
                    android:scheme="http" />
                <data
                    android:host="coolapk1s.com"
                    android:pathPattern="/web/.*"
                    android:scheme="http" />
                <data
                    android:host="coolapk1s.com"
                    android:pathPattern="/faxian/.*"
                    android:scheme="http" />
                <data
                    android:host="coolapk1s.com"
                    android:pathPattern="/t/.*"
                    android:scheme="http" />
                <data
                    android:host="coolapk1s.com"
                    android:pathPattern="/u/.*"
                    android:scheme="http" />
                <data
                    android:host="coolapk1s.com"
                    android:pathPattern="/n/.*"
                    android:scheme="http" />
                <data
                    android:host="coolapk1s.com"
                    android:pathPattern="/album/.*"
                    android:scheme="http" />
                <data
                    android:host="www.coolapk1s.com"
                    android:pathPattern="/"
                    android:scheme="http" />
                <data
                    android:host="www.coolapk1s.com"
                    android:pathPattern="/apk/.*\\..*"
                    android:scheme="http" />
                <data
                    android:host="www.coolapk1s.com"
                    android:pathPattern="/game/.*\\..*"
                    android:scheme="http" />
                <data
                    android:host="www.coolapk1s.com"
                    android:pathPattern="/feed/.*"
                    android:scheme="http" />
                <data
                    android:host="www.coolapk1s.com"
                    android:pathPattern="/web/.*"
                    android:scheme="http" />
                <data
                    android:host="www.coolapk1s.com"
                    android:pathPattern="/faxian/.*"
                    android:scheme="http" />
                <data
                    android:host="www.coolapk1s.com"
                    android:pathPattern="/t/.*"
                    android:scheme="http" />
                <data
                    android:host="www.coolapk1s.com"
                    android:pathPattern="/u/.*"
                    android:scheme="http" />
                <data
                    android:host="www.coolapk1s.com"
                    android:pathPattern="/n/.*"
                    android:scheme="http" />
                <data
                    android:host="www.coolapk1s.com"
                    android:pathPattern="/album/.*"
                    android:scheme="https" />
                <data
                    android:host="coolapk1s.com"
                    android:pathPattern="/"
                    android:scheme="https" />
                <data
                    android:host="coolapk1s.com"
                    android:pathPattern="/apk/.*\\..*"
                    android:scheme="https" />
                <data
                    android:host="coolapk1s.com"
                    android:pathPattern="/game/.*\\..*"
                    android:scheme="https" />
                <data
                    android:host="coolapk1s.com"
                    android:pathPattern="/feed/.*"
                    android:scheme="https" />
                <data
                    android:host="coolapk1s.com"
                    android:pathPattern="/web/.*"
                    android:scheme="https" />
                <data
                    android:host="coolapk1s.com"
                    android:pathPattern="/faxian/.*"
                    android:scheme="https" />
                <data
                    android:host="coolapk1s.com"
                    android:pathPattern="/t/.*"
                    android:scheme="https" />
                <data
                    android:host="coolapk1s.com"
                    android:pathPattern="/u/.*"
                    android:scheme="https" />
                <data
                    android:host="coolapk1s.com"
                    android:pathPattern="/n/.*"
                    android:scheme="https" />
                <data
                    android:host="coolapk1s.com"
                    android:pathPattern="/album/.*"
                    android:scheme="https" />
                <data
                    android:host="www.coolapk1s.com"
                    android:pathPattern="/"
                    android:scheme="https" />
                <data
                    android:host="www.coolapk1s.com"
                    android:pathPattern="/apk/.*\\..*"
                    android:scheme="https" />
                <data
                    android:host="www.coolapk1s.com"
                    android:pathPattern="/game/.*\\..*"
                    android:scheme="https" />
                <data
                    android:host="www.coolapk1s.com"
                    android:pathPattern="/feed/.*"
                    android:scheme="https" />
                <data
                    android:host="www.coolapk1s.com"
                    android:pathPattern="/web/.*"
                    android:scheme="https" />
                <data
                    android:host="www.coolapk1s.com"
                    android:pathPattern="/faxian/.*"
                    android:scheme="https" />
                <data
                    android:host="www.coolapk1s.com"
                    android:pathPattern="/t/.*"
                    android:scheme="https" />
                <data
                    android:host="www.coolapk1s.com"
                    android:pathPattern="/u/.*"
                    android:scheme="https" />
                <data
                    android:host="www.coolapk1s.com"
                    android:pathPattern="/n/.*"
                    android:scheme="https" />
                <data
                    android:host="www.coolapk1s.com"
                    android:pathPattern="/album/.*"
                    android:scheme="https" />
            </intent-filter>
        </activity>

        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_provider_paths" />
        </provider>

    </application>

</manifest>

================================================
FILE: app/src/main/assets/devicemodel.txt
================================================
1503-M02
1503-A01
1505-A01
1505-A02
1603-A03
1605-A01
1605-A02
1607-A01
1801-A01
1707-A01
1713-A01
1807-A01
1809-A01
1803-A01
1711-A01
1501-M02
1501-A02
1603-A02
1701-M01
1515-A01
1509-M02
1509-A00
1703-M01
8681-M01
8681-M02
8681-A01
8692-M02
8692-A00
H30-T00
H30-T10
H30-U10
H30-L01
H30-L01M
H30-L02
H30-C00
G750-T00
G750-U00
G750-T20
H60-L01
H60-L02
H60-L03
H60-L11
H60-L12
H60-L21
PE-TL00M
PE-TL10
PE-TL20
PE-UL00
PE-CL00
PLK-AL10
PLK-TL01H
PLK-TL00
PLK-UL00
PLK-CL00
ATH-AL00
ATH-TL00H
ATH-TL00
ATH-UL00
ATH-CL00
KNT-AL10
KNT-AL20
KNT-TL10
KNT-UL10
FRD-AL00
FRD-AL10
FRD-TL00
FRD-DL00
PRA-AL00
PRA-AL00X
PRA-TL10
EDI-AL10
EDI-DL00
NTS-AL00
DUK-AL20
DUK-TL30
JMM-AL00
JMM-AL10
JMM-TL00
JMM-TL10
STF-AL00
STF-AL10
STF-TL10
LLD-AL00
LLD-AL10
LLD-TL10
LLD-AL20
LLD-AL30
BKL-AL00
BKL-AL20
BKL-TL10
COL-AL00
COL-AL10
COL-TL00
COL-TL10
HRY-AL00
HRY-AL00a
HRY-TL00
COR-AL00
COR-AL10
COR-TL10
RVL-AL09
JSN-AL00
JSN-AL00a
JSM-TL00
ARE-AL00
ARE-AL10
ARE-TL00
TNY-AL00
TNY-TL00
PCT-AL10
PCT-TL10
HRY-AL00T
HRY-AL00Ta
HRY-TL00T
YAL-AL00
YAL-TL00
YAL-AL10
YAL-TL10
Hol-T00
Hol-U10
G750-T01
G621-TL00M
G621-TL00
G620S-UL00
C8817D
Che1-CL20
Che1-CL00
Che2-TL00
Che2-TL00H
Che2-TL00M
CHE-TL00H
CHE-TL00
Che2-UL00
CHM-TL00H
CHM-TL00
CHM-UL00
CHM-CL00
SCL-AL00
SCL-TL00H
SCL-TL00
SCL-CL00
KIW-AL00
KIW-TL00H
KIW-TL00
KIW-UL00
KIW-CL00
NEM-AL10
NEM-TL00H
NEM-TL00
NEM-UL00
CAM-AL00
CAM-TL00H
CAM-TL00
CAM-UL00
CAM-CL00
CUN-AL00
CUN-TL00
BLN-AL10
BLN-AL20
BLN-AL30
BLN-AL40
BLN-TL00
BLN-TL10
DLI-AL10
DLI-TL20
MYA-AL10
MYA-TL10
BND-AL00
BND-AL10
BND-TL10
LND-AL30
LND-AL40
LND-TL30
LND-TL40
AUM-AL00
AUM-AL20
AUM-TL00
AUM-TL20
DUA-AL00
DUA-TL00
BKK-AL00
BKK-AL10
BKK-TL00
JAT-AL00
JAT-TL00
KSA-AL00
KSA-TL00
7D-501u
7D-503L
7D-503LT
GEM-703L
GEM-703LT
S8-701w
S8-701u
T1-821w
T1-823L
JDN-W09
JDN-AL00
JDN2-W09HN
JDN2-AL00HN
AGS2-W09HN
AGS2-AL00HN
T1-701u
T1-701ua
BGO-DL09
T1-A21w
T1-A23L
KOB-W09
KOB-L09
AGS-W09
AGS-L09
BG2-W09
HDN-W09
HDN-L09
HDL-W09
HDL-AL09
HUAWEI MT1-T00
HUAWEI MT1-U06
HUAWEI MT2-U071
HUAWEI MT2-C00
HUAWEI MT2-L02
HUAWEI MT2-L05
HUAWEI MT7-TL00
HUAWEI MT7-TL10
HUAWEI MT7-UL00
HUAWEI MT7-CL00
HUAWEI CRR-TL00
HUAWEI CRR-UL00
HUAWEI CRR-UL20
HUAWEI CRR-CL00
HUAWEI CRR-CL20
HUAWEI NXT-AL10
HUAWEI NXT-TL00
HUAWEI NXT-DL00
HUAWEI NXT-CL00
MHA-AL00
MHA-TL00
LON-AL00
ALP-AL00
ALP-TL00
BLA-AL00
BLA-TL00
NEO-AL00
HMA-AL00
HMA-TL00
LYA-AL00
LYA-AL10
LYA-TL00
EVR-AL00
EVR-TL00
EVR-AN00
LYA-AL00P
HUAWEI U9200
HUAWEI U9200E
HUAWEI U9200S
HUAWEI P2-0000
HUAWEI P6-T00
HUAWEI P6-T00V
HUAWEI P6-U06
HUAWEI P6-C00
HUAWEI P6 S-U06
HUAWEI P7-L00
HUAWEI P7-L05
HUAWEI P7-L07
HUAWEI P7-L09
HUAWEI GRA-TL00
HUAWEI GRA-UL00
HUAWEI GRA-UL10
HUAWEI GRA-CL00
HUAWEI GRA-CL10
HUAWEI ALE-TL00
HUAWEI ALE-UL00
HUAWEI ALE-CL00
DAV-703L
DAV-713L
EVA-AL00
EVA-AL10
EVA-TL00
EVA-DL00
EVA-CL00
VIE-AL10
VTR-AL00
VTR-TL00
VKY-AL00
VKY-TL00
EML-AL00
EML-TL00
CLT-AL00
CLT-AL01
CLT-AL00l
CLT-TL00
CLT-TL01
ELE-AL00
ELE-TL00
VOG-AL00
VOG-AL10
VOG-TL00
HUAWEI CAZ-AL00
HUAWEI CAZ-AL10
HUAWEI CAZ-TL10
HUAWEI CAZ-TL20
WAS-AL00
WAS-TL10
PIC-AL00
PIC-TL00
BAC-AL00
BAC-TL00
HWI-AL00
HWI-TL00
ANE-AL00
ANE-TL00
PAR-AL00
PAR-TL00
INE-AL00
INE-TL00
VCE-AL00
VCE-TL00
MAR-AL00
MAR-TL00
SEA-AL00
SEA-TL00
SEA-AL10
SEA-TL10
GLK-AL00
GLK-TL00
HUAWEI G6-T00
HUAWEI G6-U00
HUAWEI G6-C00
HUAWEI G7-TL00
HUAWEI G7-UL00
HUAWEI RIO-TL00
HUAWEI RIO-UL00
HUAWEI VNS-AL00
HUAWEI VNS-TL00
HUAWEI VNS-DL00
HUAWEI VNS-CL00
HUAWEI MLA-TL00
HUAWEI MLA-TL10
HUAWEI MLA-UL00
HUAWEI A199
HUAWEI B199
HUAWEI C199
HUAWEI C199s
HUAWEI RIO-AL00
HUAWEI RIO-CL00
HUAWEI MLA-AL00
HUAWEI MLA-AL10
RNE-AL00
SNE-AL00
POT-AL00
HUAWEI TIT-AL00
HUAWEI TIT-TL00
HUAWEI TIT-CL00
HUAWEI TIT-CL10
HUAWEI TAG-AL00
HUAWEI TAG-TL00
HUAWEI TAG-CL00
NCE-AL00
NCE-AL10
NCE-TL00
NCE-TL10
DIG-AL00
DIG-TL10
SLA-AL00
SLA-TL10
TRT-AL00
TRT-AL00A
TRT-TL10
TRT-TL10A
FIG-AL00
FIG-AL10
FIG-TL00
FIG-TL10
LDN-AL00
LDN-AL10
LDN-AL20
LDN-TL00
LDN-TL10
LDN-TL20
FLA-AL00
FLA-AL10
FLA-TL00
FLA-TL10
ATU-AL10
ATU-TL10
DRA-AL00
DRA-TL00
DUB-AL00
DUB-AL00a
DUB-TL00
DUB-TL00a
JKM-AL00
JKM-AL00a
JKM-AL00b
JKM-TL00
ARS-AL00
ARS-TL00
POT-AL00
POT-AL00a
POT-TL00a
MRD-AL00
MRD-TL00
S8-301W
S8-301U
S8-303L
HUAWEI M2-801W
HUAWEI M2-803L
HUAWEI M2-A01W
HUAWEI M2-A01L
PLE-703L
PLE-703LT
FDR-A01w
FDR-A03L
BTV-W09
BTV-DL09
CPN-W09
CPN-AL00
BAH-W09
BAH-AL00
BZK-W00
BZK-L00
BZA-W00
BZA-L00
SHT-W09
SHT-AL09
CMR-W09
CMR-AL09
CMR-W19
CMR-AL19
BAH2-W09
BAH2-AL10
JDN2-W09
JDN2-AL00
MON-W19
MON-AL19
BZT-W09
BZT-AL00
BZT-AL10
AGS2-W09
AGS2-AL00
VRD-W09
VRD-AL09
SCM-W09
SCM-AL09
HUAWEI U8860
HUAWEI C8860E
HUAWEI T8950
HUAWEI U8950D
HUAWEI C8950D
HUAWEI U9508
HUAWEI HN3-U01
HUAWEI U9500
HUAWEI U9500E
HUAWEI U9510
HUAWEI U9510E
HUAWEI T9510E
HUAWEI D2-5000
HUAWEI D2-6070
HUAWEI D2-0082
HUAWEI D2-2010
Lenovo L78011
Lenovo L78012
Lenovo L78031
Lenovo L78032
Lenovo L78071
Lenovo L78051
Lenovo L78121
Lenovo L38111
Lenovo K520
Lenovo K520t
Lenovo L58041
Lenovo L58091
Lenovo K350t
Lenovo L38012
Lenovo L38011
Lenovo L38021
Lenovo L38031
Lenovo L38041
Lenovo L38082
Lenovo L18011
Lenovo K320t
Letv X600
Letv X608
Letv X500
Letv X501
Letv X508
Letv X502
Letv X800
Letv X800+
Letv X900
Letv X900+
Letv X906
Le X620
Le X621
Le X625
Le X520
Le X521
Le X528
Le X529
Le X820
Le X822
Letv X910
LEX622
LEX626
LEX623
LEX720
LEX722
LEX728
LEX726
LEX651
LEX650
LEX658
LEX652
LEX656
LEX850
M8
M8SE
M9
M030
M031
M032
M040
M045
M351
M353
M355
M356
M460
M460A
M461
M460H
M462
M462U
M462H
M575
M575M
M575U
M575H
M685Q
M685M
M685U
M685C
M685H
M576
M576U
M576H
M570Q
M570M
M570C
M570H
M570Q-S
M686
M686G
M686H
M792Q-L
M792M-L
M792C-L
M792H
M792Q
M792C
M793Q
M793H
M881Q
M881M
M881H
M891Q
M891H
M871Q
M871H
M882Q
M882H
M892Q
M872Q
M872H
M971Q
M971H
M926Q
M926H
M852Q
M852H
M813Q
M813H
M816Q
M816H
M810H
M818H
M819H
M822Q
M822H
M923Q
M923H
M463M
M463U
M463C
M463H
M571
M571M
M571U
M571C
M571H
M681Q
L681Q
M681M
L681M
M681C
L681C
M681H
L681H
M621Q
M621M
M621C
M621C-S
M621H
M721Q
M721M
M721C
M721H
A680Q
A680M
A680H
M741A
M741Y
M851Q
M851M
M682Q
M465M
M465A
M578
M578A
M578M
M578MA
M578U
M578C
M578CA
M578CE
M578H
M688Q
M688M
M688U
M688C
Y685Q
Y685M
Y685C
Y685H
M611A
M611Y
M611D
M611H
M612Q
M612M
M612C
M612H
M711Q
M711M
M711C
M711H
M712Q
M712Q-B
M712M
M712C
M712H
M811Q
M811H
S685Q
S685M
S685C
S685H
U680A
U680Y
U680D
U680H
U685Q
U685M
U685C
U685H
M57A
M57AM
M57AU
M57AC
M710M
M710H
L47M1-AA
L40M2-AA
L49M2-AA
L55M2-AA
L48M3-AA
L48M3-AR
L55M4-AA
L55M4-AR
L60M4-AA
L60M4-AR
L70M4-AA
L43M3-AA
L43M3-AR
L48M3-AF
L55M5-AA
L60M5-AA
L65M5-AA
L65M4-AQ
L32M5-AZ
L32M5-AZ
L40M5-AD
L43M5-AZ
L43M5-AD
L43M5-5A
L43M5-5A
L49M5-AZ
L50M5-AD
L50M5-5A
L50M5-5A
L55M5-AZ
L55M5-AD
L55M5-5A
L58M5-4A
L65M5-AZ
L65M5-AD
L65M5-5A
L49M5-AB
L55M5-AB
L65M5-AB
L65M5-4
L75M5-AB
L32M5-AD
L40M5-4C
L40M5-4C
L43M5-AX
L50M5-AD
L55M5-AZ
L65M5-4C
L32M5-AD
L43M5-AU
L43M5-5S
L50M5-AD
L50M5-5S
L55M5-AD
L55M5-5S
L55M5-AQ
L58M5-4C
L65M5-AD
L65M5-5S
L65M5-AD
L75M5-4S
L43M5-4X
L55M5-AD
L65M5-4X
L32M5-AD
L43M5-FA
L55M5-AZ
L55M5-EC
L65M5-EA
L55M5-AB
L65M5-4
L65M5-BH
MDZ-18-DA
MDZ-19-DA
MDZ-05-AA
MDZ-06-AA
MDZ-06-AB
MDZ-09-AA
MDZ-09-AK
MDZ-15-AA
MDZ-16-AA
MDZ-18-AA
MDZ-19-AA
MDZ-21-AA
MDZ-20-AA
MDZ-23-AA
XT1085
XT1079
XT1077
XT1115
XT1570
XT1561
XT1581
XT1635-03
XT1662
XT1650-05
XT1710-08
XT1710-11
XT1799-1
XT1799-2
XT1789-05
XT1925-10
XT1929-15
XT1924-9
XT1943-1
XT1942-1
XT1941-2
XT1965-6
TA-1000
TA-1054
TA-1041
TA-1062
TA-1042
TA-1094
TA-1109
TA-1099
TA-1131
TA-1172
TA-1117
NX501
NX401
NX402
NX503A
NX503J
NX403A
NX506J
NX507J
NX507H
NX505J
NX505H
NX508J
NX508H
NX511J
NX511H
NX510J
NX512H
NX512J
NX518J
NX531J
NX529J
NX523J
NX535J
NX549J
NX563J
NX591J
NX569J
NX569H
NX595J
NX589J
NX606J
NX611J
NX609J
NX619J
NX629J
NX601J
NX616J
NX612J
NX513J
NX513H
NX551J
NX573J
NX907J
NX541J
NX575J
NX608J
NX617J
ONE A0001
ONE A1001
ONE A2001
ONE A2003
ONE A2005
ONE E1001
ONE E1000
ONE E1003
ONE E1005
ONEPLUS A3000
ONEPLUS A3003
ONEPLUS A3010
ONEPLUS A3003
ONEPLUS A3000
ONEPLUS A5000
ONEPLUS A5010
ONEPLUS A6000
ONEPLUS A6003
ONEPLUS A6010
ONEPLUS A6013
GM1900
GM1901
GM1903
GM1905
GM1910
GM1911
GM1913
GM1915
GM1917
GM1920
ONE A0001
ONE A1001
ONE A2003
ONE A2005
ONE A2001
ONE E1003
ONE E1005
ONE E1000
ONE E1001
ONEPLUS A3003
ONEPLUS A3000
ONEPLUS A3003
ONEPLUS A3000
ONEPLUS A3010
ONEPLUS A5000
ONEPLUS A5010
ONEPLUS A6003
ONEPLUS A6000
ONEPLUS A6013
ONEPLUS A6010
GM1901
GM1903
GM1905
GM1900
GM1911
GM1913
GM1915
GM1917
GM1910
GM1920
PACM00
PACT00
PAAM00
PAAT00
PBCM10
PBCT10
PBEM00
PBET00
PBDM00
PBDT00
PAFM00
PAFT00
PAHM00
PAFT10
PCAM00
PCAT00
PCCM00
PCCT00
PCDM10
PCDT10
PADM00
PADT00
PBAM00
PBBM30
PBAT00
PBBT30
PBFM00
PBFT00
PBBM00
PBBT00
PCDM00
PCDT00
PCAM10
PCAT10
PCEM00
PCET00
PBCM30
PCGM00
PCGT00
GT-I9000
GT-I9008
GT-I9008L
SCH-i909
GT-I9100
GT-I9100G
GT-I9108
SCH-I919
GT-I9300
GT-I9308
SCH-I939
SCH-I939D
GT-I9300I
GT-I9308I
SCH-I939I
GT-I8190N
GT-I9500
GT-I9502
GT-I9508
SCH-I959
GT-I9507V
GT-I9508V
SM-C101
SM-G9006V
SM-G9008V
SM-G9009D
SM-G9006W
SM-G9008W
SM-G9009W
SM-G9200
SM-G9208
SM-G9209
SM-G9250
SM-G9280
SM-G9300
SM-G9308
SM-G9350
SM-G9500
SM-G9508
SM-G9550
SM-G9600/DS
SM-G9608/DS
SM-G9650/DS
SM-G8750
SM-G9700
SM-G9708
SM-G9730
SM-G9738
SM-G9750
SM-G9758
GT-I9220
GT-I9228
SCH-I889
GT-N7100
GT-N7102
GT-N7102i
GT-N7108
GT-N7108D
SCH-N719
SM-N9002
SM-N9006
SM-N9008
SM-N9008V
SM-N9008S
SM-N9009
SM-N7506V
SM-N7508V
SM-N7509V
SM-N9100
SM-N9106W
SM-N9108V
SM-N9109W
SM-N9150
SM-N9200
SM-N9208
SM-N9300
SM-N9500
SM-N9508
SM-N9600
SM-N9608
SM-A3000
SM-A3009
SM-A5000
SM-A5009
SM-A7000
SM-A7009
SM-A8000
SM-A5100
SM-A5108
SM-A7100
SM-A7108
SM-A9000
SM-A9100
SM-G8850
SM-G8858
SM-A6050
SM-A6058
SM-G6200
SM-G8870
SM-A9200
SM-A3050
SM-A3058
SM-A6060
SM-A7050
SM-A8050
SM-F9000
SM-C5000
SM-C5010
SM-C5018
SM-C7000
SM-C7010
SM-C7018
SM-C7100
SM-C7108
SM-C9000
SM-C9008
SM-J3109
SM-J5008
SM-J7008
SM-J3110
SM-J3119
SM-J3119S
SM-J5108
SM-J7108
SM-J7109
SM-J3300
SM-J3308
SM-G5500
SM-G6000
SM-G5700
SM-G5510
SM-G5520
SM-G5528
SM-G6100
SM-G1600
SM-G1650
SM-G8508S
SM-E7000
SM-E7009
SM701
SM705
SM801
SM901
SM919
YQ601
YQ603
YQ605
YQ607
OD103
OD105
OS105
OS103
OC105
OC106
DE106
OE106
V1814A
V1814T
V1809A
V1809T
V1816A
V1816T
V1829A
V1829T
V1838A
V1838T
V1836A
V1836T
V1821A
V1821T
V1801A0
V1730DA
V1730DT
V1730EA
V1813BA
V1813BT
V1813A
V1813T
V1813A
V1813T
V1730GA
V1911A
V1911T
V1731CA
V1732A
V1732T
V1732A
V1732T
V1818CA
V1818CT
V1818A
V1818T
V1818CA
V1818CT
V1818CA
V1818CT
V1813A
V1813T
V1901A
V1901T
V1824BA
V1824A
V1914A
V1831A
V1831T
V1832A
V1832T
V1818A
MI-ONE PLUS
MI-ONE C1
MI-ONE
2012051
2012053
2012052
2012061
2012062
2013012
2013021
2012121
2013061
2013062
2013063
2014215
2014218
2014216
2014719
2014716
2014726
2015015
2015561
2015562
2015911
2015201
2015628
2015105
2015711
2016070
2016089
MDE2
MDT2
MCE16
MCT1
M1804D2SE
M1804D2ST
M1804D2SC
M1803E1A
M1803E1T
M1803E1C
M1807E8S
M1807E8A
M1805E2A
M1808D2TE
M1808D2TT
M1808D2TC
M1808D2TG
M1902F1A
M1902F1T
M1902F1C
M1902F1G
M1903F2A
M1903F2G
M1903F10G
M1903F11G
2014616
2014619
2014618
2014617
2015011
2015021
2015022
2015501
2015211
2015212
2015213
MCE8
MCT8
2016080
MDE5
MDT5
MDE5S
M1803D5XE
M1803D5XA
M1803D5XT
M1803D5XC
M1810E5E
M1810E5A
M1810E5T
M1810E5EC
M1810E5GG
2016001
2016002
2016007
MDE40
MDT4
MDI40
M1804E4A
M1804E4T
M1804E4C
M1901F9E
M1901F9T
MDG2
MDI2
M1804D2SG
M1804D2SI
M1805D1SG
A0101
2015716
MCE91
M1806D9W
M1806D9E
M1806D9PW
M1806D9PE
2013022
2013023
2013029
2013028
2014011
2014501
2014813
2014112
2014811
2014812
2014821
2014817
2014818
2014819
2014502
2014512
2014055
2014816
2015811
2015815
2015812
2015810
2015817
2015819
2015818
2015816
2016030
2016031
2016032
2016037
2016036
2016035
2016033
2016090
2016060
2016111
2016112
2016117
2016116
MAE136
MAT136
MAG138
MAI132
MDE1
MDT1
MDG1
MDI1
MEE7
MET7
MEG7
MEI7
MCE3B
MCT3B
MCG3B
MCI3B
M1804C3DE
M1804C3DT
M1804C3DC
M1804C3DG
M1804C3DH
M1804C3DI
M1805D1SE
M1805D1ST
M1805D1SC
M1805D1SI
M1804C3CE
M1804C3CT
M1804C3CC
M1804C3CG
M1804C3CH
M1804C3CI
M1810F6LE
M1810F6LT
M1810F6LC
M1810F6LG
M1810F6LH
M1810F6LI
M1903C3EE
M1903C3ET
M1903C3EC
M1903C3EG
M1903C3EH
M1903C3EI
2014018
2013121
2014017
2013122
2014022
2014021
2014715
2014712
2014915
2014912
2014916
2014911
2014910
2015052
2015051
2015712
2015055
2015056
2015617
2015611
2015112
2015115
2015116
2015161
2016050
2016051
2016101
2016130
2016100
2016102
MBE6A5
MBT6A5
MEE7S
MET7S
MEC7S
M1803E7SG
M1803E7SH
MEI7S
MDE6
MDT6
MDG6
MDI6
MDE6S
MDT6S
MDG6S
MDI6S
M1806E7TG
M1806E7TH
M1806E7TI
M1901F7E
M1901F7T
M1901F7C
M1901F7G
M1901F7H
M1901F7I
M1901F7BE
M1901F7S
M1803E6E
M1803E6T
M1803E6C
M1803E6G
M1803E6H
M1803E6I
M1810F6G
M1810F6I
2016020
2016021
M1903F10A
M1903F10T
M1903F10C
M1903F10I
M1903F11A
M1903F11T
M1903F11C
M1903F11I
M1903C3GG
M1903C3GH
M1903C3GI
SKR-A0
AWM-A0
SKW-A0
M1805E10A

================================================
FILE: app/src/main/java/com/example/c001apk/compose/C001Application.kt
================================================
package com.example.c001apk.compose

import android.app.Application
import coil.Coil
import coil.ImageLoader
import com.example.c001apk.compose.util.dp
import dagger.hilt.android.HiltAndroidApp
import me.zhanghai.android.appiconloader.coil.AppIconFetcher
import me.zhanghai.android.appiconloader.coil.AppIconKeyer
import net.mikaelzero.coilimageloader.CoilImageLoader
import net.mikaelzero.mojito.Mojito
import net.mikaelzero.mojito.view.sketch.SketchImageLoadFactory

/**
 * Created by bggRGjQaUbCoE on 2024/5/29
 */
lateinit var c001Application: C001Application

@HiltAndroidApp
class C001Application : Application() {

    override fun onCreate() {
        super.onCreate()

        c001Application = this

        Coil.setImageLoader(
            ImageLoader.Builder(this)
                .crossfade(true)
                .components {
                    add(AppIconKeyer())
                    add(AppIconFetcher.Factory(48.dp, false, this@C001Application))
                }
                .build()
        )

        Mojito.initialize(
            CoilImageLoader.with(this),
            SketchImageLoadFactory()
        )

    }

}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/constant/Constants.kt
================================================
package com.example.c001apk.compose.constant

import com.example.c001apk.compose.util.CookieUtil.isDarkMode

/**
 * Created by bggRGjQaUbCoE on 2024/6/3
 */
object Constants {
    const val REQUEST_WITH = "XMLHttpRequest"
    const val LOCALE = "zh-CN"
    const val APP_ID = "com.coolapk.market"
    var DARK_MODE = if (isDarkMode) "1" else "0"
    const val CHANNEL = "coolapk"
    const val MODE = "universal"
    const val APP_LABEL = "token://com.coolapk.market/dcf01e569c1e3db93a3d0fcf191a622c"
    const val VERSION_NAME = "13.4.1"
    const val API_VERSION = "13"
    const val VERSION_CODE = "2312121"

    const val PREFIX_COOLMARKET = "coolmarket://"
    const val PREFIX_HTTP = "http"
    const val PREFIX_APP = "/apk/"
    const val PREFIX_GAME = "/game/"
    const val PREFIX_FEED = "/feed/"
    const val PREFIX_PRODUCT = "/product/"
    const val PREFIX_TOPIC = "/t/"
    const val PREFIX_USER = "/u/"
    const val PREFIX_CAROUSEL = "/page?url="
    const val PREFIX_CAROUSEL1 = "#/" // "#/feed/", "#/topic/", "#/article/"
    const val PREFIX_USER_LIST = "/user/"
    const val PREFIX_DYH = "/dyh/"
    const val PREFIX_COLLECTION = "/collection/"
    const val SUFFIX_THUMBNAIL = ".s.jpg"
    const val SUFFIX_GIF = ".gif"

    const val UTF8 = "UTF-8"
    const val EMPTY_STRING = ""
    const val LOADING_FAILED = "FAILED"
    const val WEB_LOGIN_FAILED = "网页登录失败"
    const val URL_LOGIN = "https://account.coolapk.com/auth/login?type=mobile"
    const val URL_SOURCE_CODE = "https://github.com/bggRGjQaUbCoE/c001apk-compose"

    val entityTypeList =
        listOf(
            "feed",
            "apk",
            "product",
            "user",
            "topic",
            "notification",
            "productBrand",
            "contacts",
            "recentHistory",
            "feed_reply",
            "message",
            "collection",
        )
    val entityTemplateList =
        listOf(
            "imageCarouselCard_1",
            "iconLinkGridCard",
            "iconMiniScrollCard",
            "iconMiniGridCard",
            "imageSquareScrollCard",
            "titleCard",
            "iconScrollCard",
            "imageTextScrollCard",
            "iconTabLinkGridCard",
            "verticalColumnsFullPageCard",
            "noMoreDataCard",
            "time",
        )

    val seedColors = listOf(
        0xFF6650A4,
        0xFFF44336,
        0xFFE91E63,
        0xFF9C27B0,
        0xFF3F51B5,
        0xFF2196F3,
        0xFF03A9F4,
        0xFF00BCD4,
        0xFF009688,
        0xFF4FAF50,
        0xFF8BC3A4,
        0xFFCDDC39,
        0xFFFFEB3B,
        0xFFFFC107,
        0xFFFF9800,
        0xFFFF5722,
        0xFF795548,
        0xFF607D8F,
        0xFFFF9CA8,
    )

}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/di/DataStoreModule.kt
================================================
package com.example.c001apk.compose.di

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.core.DataStoreFactory
import androidx.datastore.dataStoreFile
import com.example.c001apk.compose.logic.datastore.UserPreferencesCompat
import com.example.c001apk.compose.logic.datastore.UserPreferencesSerializer
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object DataStoreModule {
    @Provides
    @Singleton
    fun providesUserPreferencesDataStore(
        @ApplicationContext context: Context,
        userPreferencesSerializer: UserPreferencesSerializer
    ): DataStore<UserPreferencesCompat> =
        DataStoreFactory.create(
            serializer = userPreferencesSerializer
        ) {
            context.dataStoreFile("user_preferences.pb")
        }
}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/di/DatabaseModule.kt
================================================
package com.example.c001apk.compose.di

import android.content.Context
import androidx.room.Room
import com.example.c001apk.compose.logic.dao.HistoryFavoriteDao
import com.example.c001apk.compose.logic.dao.HomeMenuDao
import com.example.c001apk.compose.logic.dao.RecentAtUserDao
import com.example.c001apk.compose.logic.dao.StringEntityDao
import com.example.c001apk.compose.logic.database.HistoryFavoriteDatabase
import com.example.c001apk.compose.logic.database.HomeMenuDatabase
import com.example.c001apk.compose.logic.database.RecentAtUserDatabase
import com.example.c001apk.compose.logic.database.StringEntityDatabase
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Qualifier
import javax.inject.Singleton


@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class UserBlackList

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class TopicBlackList

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class SearchHistory

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class RecentEmoji

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class BrowseHistory

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class FeedFavorite

@Module
@InstallIn(SingletonComponent::class)
object DatabaseModule {

    @RecentEmoji
    @Singleton
    @Provides
    fun provideRecentEmojiDao(@RecentEmoji stringEntityDatabase: StringEntityDatabase): StringEntityDao {
        return stringEntityDatabase.stringEntityDao()
    }

    @RecentEmoji
    @Singleton
    @Provides
    fun provideRecentEmojiDatabase(@ApplicationContext context: Context): StringEntityDatabase {
        return Room.databaseBuilder(
            context.applicationContext,
            StringEntityDatabase::class.java, "recent_emoji"
        )
            .build()
    }

    @UserBlackList
    @Singleton
    @Provides
    fun provideUserBlackListDao(@UserBlackList stringEntityDatabase: StringEntityDatabase): StringEntityDao {
        return stringEntityDatabase.stringEntityDao()
    }

    @UserBlackList
    @Singleton
    @Provides
    fun provideUserBlackListDatabase(@ApplicationContext context: Context): StringEntityDatabase {
        return Room.databaseBuilder(
            context.applicationContext,
            StringEntityDatabase::class.java, "user_blacklist"
        )
            .build()
    }

    @TopicBlackList
    @Singleton
    @Provides
    fun provideTopicBlackListDao(@TopicBlackList stringEntityDatabase: StringEntityDatabase): StringEntityDao {
        return stringEntityDatabase.stringEntityDao()
    }

    @TopicBlackList
    @Singleton
    @Provides
    fun provideTopicBlackListDatabase(@ApplicationContext context: Context): StringEntityDatabase {
        return Room.databaseBuilder(
            context.applicationContext,
            StringEntityDatabase::class.java, "topic_blacklist"
        )
            .build()
    }

    @SearchHistory
    @Singleton
    @Provides
    fun provideSearchHistoryDao(@SearchHistory stringEntityDatabase: StringEntityDatabase): StringEntityDao {
        return stringEntityDatabase.stringEntityDao()
    }

    @SearchHistory
    @Singleton
    @Provides
    fun provideSearchHistoryDatabase(@ApplicationContext context: Context): StringEntityDatabase {
        return Room.databaseBuilder(
            context.applicationContext,
            StringEntityDatabase::class.java, "search_history"
        )
            .build()
    }

    @BrowseHistory
    @Singleton
    @Provides
    fun provideBrowseHistoryDao(@BrowseHistory browseHistoryDatabase: HistoryFavoriteDatabase): HistoryFavoriteDao {
        return browseHistoryDatabase.historyFavoriteDao()
    }

    @BrowseHistory
    @Singleton
    @Provides
    fun provideBrowseHistoryDatabase(@ApplicationContext context: Context): HistoryFavoriteDatabase {
        return Room.databaseBuilder(
            context.applicationContext,
            HistoryFavoriteDatabase::class.java, "browse_history"
        ).build()
    }

    @FeedFavorite
    @Singleton
    @Provides
    fun provideFeedFavoriteDao(@FeedFavorite feedFavoriteDatabase: HistoryFavoriteDatabase): HistoryFavoriteDao {
        return feedFavoriteDatabase.historyFavoriteDao()
    }

    @FeedFavorite
    @Singleton
    @Provides
    fun provideFeedFavoriteDatabase(@ApplicationContext context: Context): HistoryFavoriteDatabase {
        return Room.databaseBuilder(
            context.applicationContext,
            HistoryFavoriteDatabase::class.java, "feed_favorite"
        )
            .build()
    }

    @Singleton
    @Provides
    fun provideHomeMenuDao(homeMenuDatabase: HomeMenuDatabase): HomeMenuDao {
        return homeMenuDatabase.homeMenuDao()
    }

    @Singleton
    @Provides
    fun provideHomeMenuDatabase(@ApplicationContext context: Context): HomeMenuDatabase {
        return Room.databaseBuilder(
            context.applicationContext,
            HomeMenuDatabase::class.java, "home_menu"
        )
            .build()
    }

    @Singleton
    @Provides
    fun provideRecentAtUserDao(recentAtUserDatabase: RecentAtUserDatabase): RecentAtUserDao {
        return recentAtUserDatabase.recentAtUserDao()
    }

    @Singleton
    @Provides
    fun provideRecentAtUserDatabase(@ApplicationContext context: Context): RecentAtUserDatabase {
        return Room.databaseBuilder(
            context.applicationContext,
            RecentAtUserDatabase::class.java, "recent_at_user"
        )
            .build()
    }

}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/di/NetworkModule.kt
================================================
package com.example.c001apk.compose.di

import com.example.c001apk.compose.BuildConfig
import com.example.c001apk.compose.logic.network.ApiService
import com.example.c001apk.compose.util.AddCookiesInterceptor
import com.example.c001apk.compose.util.LoginCookiesInterceptor
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import javax.inject.Qualifier
import javax.inject.Singleton

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class Api1Service

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class Api1ServiceNoRedirect

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class Api2Service

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class AccountService

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {

    private const val API_BASE_URL = "https://api.coolapk.com"
    private const val API2_BASE_URL = "https://api2.coolapk.com"
    private const val ACCOUNT_BASE_URL = "https://account.coolapk.com"

    @Api1Service
    @Singleton
    @Provides
    fun provideApi1Service(@Api1Service retrofit: Retrofit): ApiService {
        return retrofit.create(ApiService::class.java)
    }

    @Api1ServiceNoRedirect
    @Singleton
    @Provides
    fun provideApi1ServiceNo(@Api1ServiceNoRedirect retrofit: Retrofit): ApiService {
        return retrofit.create(ApiService::class.java)
    }

    @Api2Service
    @Singleton
    @Provides
    fun provideApi2Service(@Api2Service retrofit: Retrofit): ApiService {
        return retrofit.create(ApiService::class.java)
    }

    @AccountService
    @Singleton
    @Provides
    fun provideAccountService(@AccountService retrofit: Retrofit): ApiService {
        return retrofit.create(ApiService::class.java)
    }

    @Api1Service
    @Singleton
    @Provides
    fun provideApi1ServiceRetrofit(@Api1Service okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .baseUrl(API_BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(okHttpClient)
            .build()
    }

    @Api1ServiceNoRedirect
    @Singleton
    @Provides
    fun provideApi1ServiceNoRetrofit(@Api1ServiceNoRedirect okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .baseUrl(API_BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(okHttpClient)
            .build()
    }

    @Api2Service
    @Singleton
    @Provides
    fun provideApi2ServiceRetrofit(@Api1Service okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .baseUrl(API2_BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(okHttpClient)
            .build()
    }

    @AccountService
    @Singleton
    @Provides
    fun provideAccountServiceRetrofit(@AccountService okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .baseUrl(ACCOUNT_BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(okHttpClient)
            .build()
    }

    @Api1Service
    @Singleton
    @Provides
    fun provideOkHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
            .addInterceptor(AddCookiesInterceptor)
            .addInterceptor(
                HttpLoggingInterceptor().setLevel(
                    if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY
                    else HttpLoggingInterceptor.Level.NONE
                )
            )
            .followRedirects(true)
            .build()
    }

    @Api1ServiceNoRedirect
    @Singleton
    @Provides
    fun provideNoOkHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
            .addInterceptor(AddCookiesInterceptor)
            .addInterceptor(
                HttpLoggingInterceptor().setLevel(
                    if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY
                    else HttpLoggingInterceptor.Level.NONE
                )
            )
            .followRedirects(false)
            .build()
    }

    @AccountService
    @Singleton
    @Provides
    fun provideAccountServiceOkHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
            .addInterceptor(LoginCookiesInterceptor)
            .addInterceptor(
                HttpLoggingInterceptor().setLevel(
                    if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY
                    else HttpLoggingInterceptor.Level.NONE
                )
            )
            .build()
    }

}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/dao/HistoryFavoriteDao.kt
================================================
package com.example.c001apk.compose.logic.dao

import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import com.example.c001apk.compose.logic.model.FeedEntity
import kotlinx.coroutines.flow.Flow


@Dao
interface HistoryFavoriteDao {

    @Insert
    suspend fun insert(data: FeedEntity)

    @Query("SELECT * FROM FeedEntity ORDER BY time DESC")
    suspend fun loadAllList(): List<FeedEntity>

    @Query("SELECT * FROM FeedEntity ORDER BY time DESC")
    fun loadAllListLive(): LiveData<List<FeedEntity>>

    @Query("SELECT * FROM FeedEntity ORDER BY time DESC")
    fun loadAllListFlow(): Flow<List<FeedEntity>>

    @Query("SELECT 1 FROM FeedEntity WHERE id = :id LIMIT 1")
    suspend fun isExist(id: String): Boolean

    @Query("DELETE FROM FeedEntity WHERE id = :id")
    suspend fun delete(id: String)

    @Query("DELETE FROM FeedEntity")
    suspend fun deleteAll()

    @Query("DELETE FROM FeedEntity WHERE uid = :uid")
    suspend fun deleteByUid(uid:String)

}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/dao/HomeMenuDao.kt
================================================
package com.example.c001apk.compose.logic.dao

import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import com.example.c001apk.compose.logic.model.HomeMenu
import kotlinx.coroutines.flow.Flow


@Dao
interface HomeMenuDao {

    @Insert
    suspend fun insert(menu: HomeMenu)

    @Insert
    suspend fun insertList(list: List<HomeMenu>)

    @Query("SELECT * FROM HomeMenu ORDER BY position ASC")
    suspend fun loadAllList(): List<HomeMenu>

    @Query("SELECT * FROM HomeMenu ORDER BY position ASC")
    fun loadAllListLive(): LiveData<List<HomeMenu>>

    @Query("SELECT * FROM HomeMenu ORDER BY position ASC")
    fun loadAllListFlow(): Flow<List<HomeMenu>>

    @Query("SELECT 1 FROM HomeMenu WHERE title = :title LIMIT 1")
    suspend fun isExist(title: String): Boolean

    @Query("DELETE FROM HomeMenu WHERE title = :title")
    suspend fun delete(title: String)

    @Query("DELETE FROM HomeMenu")
    suspend fun deleteAll()

    @Update
    suspend fun updateList(list:List<HomeMenu>)

}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/dao/RecentAtUserDao.kt
================================================
package com.example.c001apk.compose.logic.dao

import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Transaction
import com.example.c001apk.compose.logic.model.RecentAtUser
import kotlinx.coroutines.flow.Flow


@Dao
interface RecentAtUserDao {

    @Insert
    suspend fun insert(data: RecentAtUser)

    @Insert
    suspend fun insertList(list: List<RecentAtUser>)

    @Query("SELECT * FROM RecentAtUser ORDER BY id DESC")
    suspend fun loadAllList(): List<RecentAtUser>

    @Query("SELECT * FROM RecentAtUser ORDER BY id DESC")
    fun loadAllListLive(): LiveData<List<RecentAtUser>>

    @Query("SELECT * FROM RecentAtUser ORDER BY id DESC")
    fun loadAllListFlow(): Flow<List<RecentAtUser>>

    @Query("SELECT 1 FROM RecentAtUser WHERE username = :username LIMIT 1")
    suspend fun isExist(username: String): Boolean

    @Transaction
    @Query("SELECT 1 FROM RecentAtUser WHERE :username LIKE '%' || username || '%' LIMIT 1")
    suspend fun isContain(username: String): Boolean

    @Query("DELETE FROM RecentAtUser WHERE username = :username")
    suspend fun delete(username: String)

    @Delete
    suspend fun delete(data: RecentAtUser)

    @Query("DELETE FROM RecentAtUser")
    suspend fun deleteAll()

    @Query("UPDATE RecentAtUser SET id = :newId WHERE username = :username")
    suspend fun updateUser(username: String, newId: Long)

}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/dao/StringEntityDao.kt
================================================
package com.example.c001apk.compose.logic.dao

import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Transaction
import com.example.c001apk.compose.logic.model.StringEntity
import kotlinx.coroutines.flow.Flow


@Dao
interface StringEntityDao {

    @Insert
    suspend fun insert(data: StringEntity)

    @Insert
    suspend fun insertList(list: List<StringEntity>)

    @Query("SELECT * FROM StringEntity ORDER BY id DESC")
    suspend fun loadAllList(): List<StringEntity>

    @Query("SELECT * FROM StringEntity ORDER BY id DESC")
    fun loadAllListLive(): LiveData<List<StringEntity>>

    @Query("SELECT * FROM StringEntity ORDER BY id DESC")
    fun loadAllListFlow(): Flow<List<StringEntity>>

    @Query("SELECT 1 FROM StringEntity WHERE data = :data LIMIT 1")
    suspend fun isExist(data: String): Boolean

    @Transaction
    @Query("SELECT 1 FROM StringEntity WHERE :data LIKE '%' || data || '%' LIMIT 1")
    suspend fun isContain(data: String): Boolean

    @Query("DELETE FROM StringEntity WHERE data = :data")
    suspend fun delete(data: String)

    @Delete
    suspend fun delete(data: StringEntity)

    @Query("DELETE FROM StringEntity")
    suspend fun deleteAll()

    @Query("UPDATE StringEntity SET id = :newId WHERE data = :data")
    suspend fun updateHistory(data: String, newId: Long)

    @Query("UPDATE StringEntity SET id = :newId , data = :newData WHERE data = :oldData")
    suspend fun updateEmoji(oldData: String, newData: String, newId: Long)

}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/database/HistoryFavoriteDatabase.kt
================================================
package com.example.c001apk.compose.logic.database

import androidx.room.Database
import androidx.room.RoomDatabase
import com.example.c001apk.compose.logic.dao.HistoryFavoriteDao
import com.example.c001apk.compose.logic.model.FeedEntity


@Database(version = 1, entities = [FeedEntity::class])
abstract class HistoryFavoriteDatabase : RoomDatabase() {
    abstract fun historyFavoriteDao(): HistoryFavoriteDao
}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/database/HomeMenuDatabase.kt
================================================
package com.example.c001apk.compose.logic.database

import androidx.room.Database
import androidx.room.RoomDatabase
import com.example.c001apk.compose.logic.dao.HomeMenuDao
import com.example.c001apk.compose.logic.model.HomeMenu

@Database(version = 1, entities = [HomeMenu::class])
abstract class HomeMenuDatabase : RoomDatabase() {
    abstract fun homeMenuDao(): HomeMenuDao
}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/database/RecentAtUserDatabase.kt
================================================
package com.example.c001apk.compose.logic.database

import androidx.room.Database
import androidx.room.RoomDatabase
import com.example.c001apk.compose.logic.dao.RecentAtUserDao
import com.example.c001apk.compose.logic.model.RecentAtUser

@Database(version = 1, entities = [RecentAtUser::class])
abstract class RecentAtUserDatabase : RoomDatabase() {
    abstract fun recentAtUserDao(): RecentAtUserDao
}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/database/StringEntityDatabase.kt
================================================
package com.example.c001apk.compose.logic.database

import androidx.room.Database
import androidx.room.RoomDatabase
import com.example.c001apk.compose.logic.dao.StringEntityDao
import com.example.c001apk.compose.logic.model.StringEntity

@Database(version = 1, entities = [StringEntity::class])
abstract class StringEntityDatabase : RoomDatabase() {
    abstract fun stringEntityDao(): StringEntityDao
}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/datastore/UserPreferencesCompat.kt
================================================
package com.example.c001apk.compose.logic.datastore

import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.Composable
import com.example.c001apk.compose.FollowType
import com.example.c001apk.compose.ThemeMode
import com.example.c001apk.compose.ThemeType
import com.example.c001apk.compose.UserPreferences
import com.example.c001apk.compose.constant.Constants.API_VERSION
import com.example.c001apk.compose.constant.Constants.EMPTY_STRING
import com.example.c001apk.compose.constant.Constants.VERSION_CODE
import com.example.c001apk.compose.constant.Constants.VERSION_NAME

data class UserPreferencesCompat(
    val themeMode: ThemeMode,
    val materialYou: Boolean,
    val pureBlack: Boolean,
    val fontScale: Float,
    val contentScale: Float,
    val szlmId: String,
    val imageQuality: Int,
    val imageFilter: Boolean,
    val openInBrowser: Boolean,
    val showSquare: Boolean,
    val recordHistory: Boolean,
    val showEmoji: Boolean,
    val checkUpdate: Boolean,
    val checkCount: Boolean,
    val versionName: String,
    val apiVersion: String,
    val versionCode: String,
    val manufacturer: String,
    val brand: String,
    val model: String,
    val buildNumber: String,
    val sdkInt: String,
    val androidVersion: String,
    val userAgent: String,
    val xAppDevice: String,
    val xAppToken: String,
    val isLogin: Boolean,
    val userAvatar: String,
    val username: String,
    val level: String,
    val experience: String,
    val nextLevelExperience: String,
    val uid: String,
    val token: String,
    val followType: FollowType,
    val recentIds: String,
    val checkCountPeriod: Int,
    val installTime: String,
    val themeType: ThemeType,
    val seedColor: String,
    val paletteStyle: Int,
) {
    constructor(original: UserPreferences) : this(
        themeMode = original.themeMode,
        materialYou = original.materialYou,
        pureBlack = original.pureBlack,
        fontScale = original.fontScale,
        contentScale = original.contentScale,
        szlmId = original.szlmId,
        imageQuality = original.imageQuality,
        imageFilter = original.imageFilter,
        openInBrowser = original.openInBrowser,
        showSquare = original.showSquare,
        recordHistory = original.recordHistory,
        showEmoji = original.showEmoji,
        checkUpdate = original.checkUpdate,
        checkCount = original.checkCount,
        versionName = original.versionName,
        apiVersion = original.apiVersion,
        versionCode = original.versionCode,
        manufacturer = original.manufacturer,
        brand = original.brand,
        model = original.model,
        buildNumber = original.buildNumber,
        sdkInt = original.sdkInt,
        androidVersion = original.androidVersion,
        userAgent = original.userAgent,
        xAppDevice = original.xAppDevice,
        xAppToken = original.xAppToken,
        isLogin = original.isLogin,
        userAvatar = original.userAvatar,
        username = original.username,
        level = original.level,
        experience = original.experience,
        nextLevelExperience = original.nextLevelExperience,
        uid = original.uid,
        token = original.token,
        followType = original.followType,
        recentIds = original.recentIds,
        checkCountPeriod = original.checkCountPeriod,
        installTime = original.installTime,
        themeType = original.themeType,
        seedColor = original.seedColor,
        paletteStyle = original.paletteStyle,
    )

    @Composable
    fun isDarkMode() = when (themeMode) {
        ThemeMode.ALWAYS_OFF -> false
        ThemeMode.ALWAYS_ON -> true
        else -> isSystemInDarkTheme()
    }

    fun toProto(): UserPreferences = UserPreferences.newBuilder()
        .setThemeMode(themeMode)
        .setMaterialYou(materialYou)
        .setPureBlack(pureBlack)
        .setFontScale(fontScale)
        .setContentScale(contentScale)
        .setSzlmId(szlmId)
        .setImageQuality(imageQuality)
        .setImageFilter(imageFilter)
        .setOpenInBrowser(openInBrowser)
        .setShowSquare(showSquare)
        .setRecordHistory(recordHistory)
        .setShowEmoji(showEmoji)
        .setCheckUpdate(checkUpdate)
        .setCheckCount(checkCount)
        .setVersionName(versionName)
        .setApiVersion(apiVersion)
        .setVersionCode(versionCode)
        .setManufacturer(manufacturer)
        .setBrand(brand)
        .setModel(model)
        .setBuildNumber(buildNumber)
        .setSdkInt(sdkInt)
        .setAndroidVersion(androidVersion)
        .setUserAgent(userAgent)
        .setXAppDevice(xAppDevice)
        .setXAppToken(xAppToken)
        .setIsLogin(isLogin)
        .setUserAvatar(userAvatar)
        .setUsername(username)
        .setLevel(level)
        .setExperience(experience)
        .setNextLevelExperience(nextLevelExperience)
        .setUid(uid)
        .setToken(token)
        .setFollowType(followType)
        .setRecentIds(recentIds)
        .setCheckCountPeriod(checkCountPeriod)
        .setInstallTime(installTime)
        .setThemeType(themeType)
        .setSeedColor(seedColor)
        .setPaletteStyle(paletteStyle)
        .build()

    companion object {
        fun default() = UserPreferencesCompat(
            themeMode = ThemeMode.FOLLOW_SYSTEM,
            materialYou = true,
            pureBlack = false,
            fontScale = 1.00f,
            contentScale = 1.00f,
            szlmId = EMPTY_STRING,
            imageQuality = 0,
            imageFilter = true,
            openInBrowser = false,
            showSquare = true,
            recordHistory = true,
            showEmoji = true,
            checkUpdate = true,
            checkCount = true,
            versionName = VERSION_NAME,
            apiVersion = API_VERSION,
            versionCode = VERSION_CODE,
            manufacturer = EMPTY_STRING,
            brand = EMPTY_STRING,
            model = EMPTY_STRING,
            buildNumber = EMPTY_STRING,
            sdkInt = EMPTY_STRING,
            androidVersion = EMPTY_STRING,
            userAgent = EMPTY_STRING,
            xAppDevice = EMPTY_STRING,
            xAppToken = EMPTY_STRING,
            isLogin = false,
            userAvatar = EMPTY_STRING,
            username = EMPTY_STRING,
            level = EMPTY_STRING,
            experience = EMPTY_STRING,
            nextLevelExperience = EMPTY_STRING,
            uid = EMPTY_STRING,
            token = EMPTY_STRING,
            followType = FollowType.ALL,
            recentIds = EMPTY_STRING,
            checkCountPeriod = 5,
            installTime = EMPTY_STRING,
            themeType = ThemeType.Default,
            seedColor = EMPTY_STRING,
            paletteStyle = 0,
        )
    }
}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/datastore/UserPreferencesDataSource.kt
================================================
package com.example.c001apk.compose.logic.datastore

import androidx.datastore.core.DataStore
import com.example.c001apk.compose.FollowType
import com.example.c001apk.compose.ThemeMode
import com.example.c001apk.compose.ThemeType
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import javax.inject.Inject

class UserPreferencesDataSource @Inject constructor(
    private val userPreferences: DataStore<UserPreferencesCompat>
) {
    val data get() = userPreferences.data

    suspend fun setThemeMode(value: ThemeMode) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(themeMode = value) }
    }

    suspend fun setMaterialYou(value: Boolean) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(materialYou = value) }
    }

    suspend fun setPureBlack(value: Boolean) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(pureBlack = value) }
    }

    suspend fun setFontScale(value: Float) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(fontScale = value) }
    }

    suspend fun setContentScale(value: Float) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(contentScale = value) }
    }

    suspend fun setSZLMId(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(szlmId = value) }
    }

    suspend fun setImageQuality(value: Int) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(imageQuality = value) }
    }

    suspend fun setImageFilter(value: Boolean) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(imageFilter = value) }
    }

    suspend fun setOpenInBrowser(value: Boolean) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(openInBrowser = value) }
    }

    suspend fun setShowSquare(value: Boolean) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(showSquare = value) }
    }

    suspend fun setRecordHistory(value: Boolean) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(recordHistory = value) }
    }

    suspend fun setShowEmoji(value: Boolean) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(showEmoji = value) }
    }

    suspend fun setCheckUpdate(value: Boolean) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(checkUpdate = value) }
    }

    suspend fun setCheckCount(value: Boolean) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(checkCount = value) }
    }

    suspend fun setVersionName(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(versionName = value) }
    }

    suspend fun setApiVersion(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(apiVersion = value) }
    }

    suspend fun setVersionCode(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(versionCode = value) }
    }

    suspend fun setManufacturer(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(manufacturer = value) }
    }

    suspend fun setBrand(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(brand = value) }
    }

    suspend fun setModel(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(model = value) }
    }

    suspend fun setBuildNumber(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(buildNumber = value) }
    }

    suspend fun setSdkInt(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(sdkInt = value) }
    }

    suspend fun setAndroidVersion(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(androidVersion = value) }
    }

    suspend fun setUserAgent(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(userAgent = value) }
    }

    suspend fun setXAppDevice(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(xAppDevice = value) }
    }

    suspend fun setXAppToken(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(xAppToken = value) }
    }

    suspend fun setIsLogin(value: Boolean) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(isLogin = value) }
    }

    suspend fun setUserAvatar(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(userAvatar = value) }
    }

    suspend fun setUsername(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(username = value) }
    }

    suspend fun setLevel(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(level = value) }
    }

    suspend fun setExperience(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(experience = value) }
    }

    suspend fun setNextLevelExperience(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(nextLevelExperience = value) }
    }

    suspend fun setUid(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(uid = value) }
    }

    suspend fun setToken(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(token = value) }
    }

    suspend fun setFollowType(value: FollowType) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(followType = value) }
    }

    suspend fun setRecentIds(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(recentIds = value) }
    }

    suspend fun setCheckCountPeriod(value: Int) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(checkCountPeriod = value) }
    }

    suspend fun setInstallTime(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(installTime = value) }
    }

    suspend fun setThemeType(value: ThemeType) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(themeType = value) }
    }

    suspend fun setSeedColor(value: String) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(seedColor = value) }
    }

    suspend fun setPaletteStyle(value: Int) = withContext(Dispatchers.IO) {
        userPreferences.updateData { it.copy(paletteStyle = value) }
    }

}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/datastore/UserPreferencesSerializer.kt
================================================
package com.example.c001apk.compose.logic.datastore

import androidx.datastore.core.CorruptionException
import androidx.datastore.core.Serializer
import com.example.c001apk.compose.UserPreferences
import com.google.protobuf.InvalidProtocolBufferException
import java.io.InputStream
import java.io.OutputStream
import javax.inject.Inject

class UserPreferencesSerializer @Inject constructor() : Serializer<UserPreferencesCompat> {
    override val defaultValue = UserPreferencesCompat.default()

    override suspend fun readFrom(input: InputStream) =
        try {
            UserPreferences.parseFrom(input).let(::UserPreferencesCompat)
        } catch (e: InvalidProtocolBufferException) {
            throw CorruptionException("cannot read proto", e)
        }

    override suspend fun writeTo(t: UserPreferencesCompat, output: OutputStream) {
        t.toProto().writeTo(output)
    }
}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/AppItem.kt
================================================
package com.example.c001apk.compose.logic.model

import android.content.pm.PackageInfo

data class AppItem(
    var label: String,
    val packageInfo: PackageInfo
)

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/CheckCountResponse.kt
================================================
package com.example.c001apk.compose.logic.model

import com.google.gson.annotations.SerializedName

data class CheckCountResponse(
    val status: Int?,
    val message: String?,
    val messageStatus: String?,
    val data: Data?
) {

    data class Data(
        val notification: Int,
        @SerializedName("contacts_follow")
        val contactsFollow: Int,
        val message: Int,
        val atme: Int,
        val atcommentme: Int,
        val commentme: Int,
        val feedlike: Int,
        val badge: Int,
        val dateline: String
    )

}



================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/CheckResponse.kt
================================================
package com.example.c001apk.compose.logic.model

import com.google.gson.annotations.SerializedName

data class CheckResponse(
    val status: Int?,
    val message: String?,
    val messageStatus: String?,
    val data: Data?
) {

    data class Data(
        val id: String?,
        val status: Int,
        @SerializedName("message_status") val messageStatus: Int?,
        val uid: String,
        val username: String,
        val token: String,
        val refreshToken: String,
        val userAvatar: String,
        val notifyCount: NotifyCount,
    )

    data class NotifyCount(
        val notification: Int,
        @SerializedName("contacts_follow") val contactsFollow: Int,
        val message: Int,
        val atme: Int,
        val atcommentme: Int,
        val commentme: Int,
        val feedlike: Int,
        val badge: Int,
        val dateline: String
    )

}



================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/CreateFeedResponse.kt
================================================
package com.example.c001apk.compose.logic.model

import com.google.gson.annotations.SerializedName

data class CreateFeedResponse(
    val status: Int?,
    val error: Int?,
    val message: String?,
    val messageStatus: String?,
    val data: Data?
) {
    data class Data(
        val status: Int?,
        val error: Int?,
        val messageStatus: String?,
        val id: String?,
        val type: String?,
        val message: String?,
        val pic: String,
        @SerializedName("device_title") val deviceTitle: String?,
        @SerializedName("message_signature") val messageSignature: String?,
        val picArr: List<String>?,
    )
}


================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/DeviceInfo.kt
================================================
package com.example.c001apk.compose.logic.model

data class DeviceInfo(
    val deviceId: String,
    val mac: String,
    val manufacturer: String,
    val brand: String,
    val model: String,
    val display: String,
    val oaid: String
)


================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/FeedAdapter.kt
================================================
package com.example.c001apk.compose.logic.model

import com.example.c001apk.compose.logic.model.HomeFeedResponse.Feed
import com.google.gson.Gson
import com.google.gson.TypeAdapter
import com.google.gson.TypeAdapterFactory
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import java.io.IOException

object FeedAdapterFactory : TypeAdapterFactory {
    override fun <T> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T> {
        return FeedAdapter(gson) as TypeAdapter<T>
    }
}

class FeedAdapter(private val gson: Gson) : TypeAdapter<Feed?>() {
    @Throws(IOException::class)
    override fun write(jsonWriter: JsonWriter, feed: Feed?) {
        throw RuntimeException("Not implemented")
    }

    @Throws(IOException::class)
    override fun read(jsonReader: JsonReader): Feed? {
        return when (jsonReader.peek()) {
            JsonToken.NUMBER -> Feed(id = jsonReader.nextInt().toString())

            JsonToken.BEGIN_OBJECT ->
                gson.fromJson(jsonReader, Feed::class.java)

            else -> throw RuntimeException("Expected object or int, not " + jsonReader.peek())
        }
    }
}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/FeedArticleContentBean.kt
================================================
package com.example.c001apk.compose.logic.model

import java.util.UUID

data class FeedArticleContentBean(
    val key: String = UUID.randomUUID().toString(),
    val type: String?,
    val message: String?,
    val url: String?,
    val description: String?,
    val title: String?,
    val subTitle: String?,
    val logo: String?,
)

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/FeedContentResponse.kt
================================================
package com.example.c001apk.compose.logic.model

import android.os.Parcelable
import kotlinx.parcelize.Parcelize

@Parcelize
data class FeedContentResponse(
    val status: Int?,
    val error: Int?,
    val message: String?,
    val messageStatus: String?,
    val data: HomeFeedResponse.Data?,
) : Parcelable



================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/FeedEntity.kt
================================================
package com.example.c001apk.compose.logic.model

import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity
data class FeedEntity(
    @PrimaryKey(autoGenerate = false)
    val id: String,
    val uid: String,
    val uname: String,
    val avatar: String,
    val device: String,
    val message: String,
    val pubDate: String,
    val time: String = System.currentTimeMillis().toString(),
)

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/HomeFeedResponse.kt
================================================
package com.example.c001apk.compose.logic.model


import android.os.Parcelable
import com.google.gson.annotations.JsonAdapter
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize

data class HomeFeedResponse(
    val status: Int?,
    val error: Int?,
    val message: String?,
    val messageStatus: Int?,
    val data: List<Data>?,
) {

    @Parcelize
    data class Data(
        val isStickTop: Int?,
        val likeUserInfo: UserInfo?,
        val ukey: String?,
        val islast: Int?,
        val isnew: Int?,
        @SerializedName("message_pic")
        val messagePic: String?,
        val messageUid: String?,
        val messageUsername: String?,
        val messageUserAvatar: String?,
        var unreadNum: Int?,
        @SerializedName("is_top")
        var isTop: Int?,
        val shorttitle: String?,
        val packageName: String?,
        @SerializedName("pkg_bit_type")
        val pkgBitType: Int?,
        var localVersionName: String?,
        var localVersionCode: Long?,
        var expand: Boolean = false,
        val forwardid: String?,
        @SerializedName("source_id")
        val sourceId: String?,
        val istag: Int?,
        val likeUsername: String?,
        val likeUid: String?,
        val likeAvatar: String?,
        val fromUserAvatar: String?,
        val fromusername: String?,
        val fromuid: String?,
        val note: String?,
        @SerializedName("extra_key")
        val extraKey: String?,
        val feedUid: String?,
        val fuid: String?,
        val rid: Long?,
        val forwardSourceType: String?,
        val forwardSourceFeed: ForwardSourceFeed?,
        @SerializedName("comment_num")
        val commentNum: String?,
        @SerializedName("fans_num")
        val fansNum: String?,
        @SerializedName("target_id")
        val targetId: String?,
        @SerializedName("target_type")
        val targetType: String?,
        @SerializedName("target_type_title")
        val targetTypeTitle: String?,
        var replyMeRows: List<Data>?,
        @SerializedName("cover_pic")
        val coverPic: String?,
        @SerializedName("is_open")
        val isOpen: Int?,
        @SerializedName("is_open_title")
        val isOpenTitle: String?,
        @SerializedName("item_num")
        val itemNum: String?,
        @SerializedName("follow_num")
        val followNum: String?,
        var description: String?,
        val subTitle: String?,
        val likeTime: Long?,
        @SerializedName("extra_title")
        val extraTitle: String?,
        @SerializedName("extra_url")
        val extraUrl: String?,
        @SerializedName("extra_pic")
        val extraPic: String?,
        val feedTypeName: String?,
        val vote: Vote?,
        @SerializedName("message_cover")
        val messageCover: String?,
        @SerializedName("message_title")
        val messageTitle: String?,
        @SerializedName("message_raw_output")
        val messageRawOutput: String?,
        val relationRows: ArrayList<RelationRows>?,
        val targetRow: TargetRow?,
        @SerializedName("change_count")
        val changeCount: Int?,
        val isModified: Int?,
        @SerializedName("ip_location")
        val ipLocation: String?,
        val isFeedAuthor: Int?,
        var topReplyRows: List<Data>?,
        val extraDataArr: ExtraDataArr?,
        val intro: String?,
        @SerializedName("tag_pics")
        val tagPics: List<String>?,
        val tabList: List<TabList>?,
        val displayUsername: String?,
        val cover: String?,
        val selectedTab: String?,
        val homeTabCardRows: List<HomeTabCardRows>?,
        @SerializedName("be_like_num")
        val beLikeNum: String?,
        val version: String?,
        val apkversionname: String?,
        val apkversioncode: String?,
        val apksize: String?,
        val apkfile: String?,
        val lastupdate: Long?,
        val follow: String?,
        val level: String?,
        val fans: String?,
        val logintime: Long?,
        val experience: String?,
        val regdate: Long?,
        @SerializedName("next_level_experience")
        val nextLevelExperience: String?,
        val bio: String?,
        @JsonAdapter(FeedAdapterFactory::class)
        val feed: Feed?,
        val gender: Int?,
        val city: String?,
        val downnum: String?,
        val downCount: String?,
        val apkname: String?,
        val entityType: String?,
        val type: String?,
        val feedType: String?,
        val fetchType: String?,
        val entityTemplate: String?,
        var entities: MutableList<Entities>?,
        val id: String?,
        val fid: String?,
        val url: String?,
        val uid: String?,
        val ruid: String?,
        val changelog: String?,
        var username: String?,
        val rusername: String?,
        val tpic: String?,
        val message: String?,
        val pic: String?,
        val tags: String?,
        val ttitle: String?,
        var likenum: String?,
        val commentnum: String?,
        val replynum: String?,
        val forwardnum: String?,
        val favnum: String?,
        val dateline: Long?,
        @SerializedName("create_time")
        val createTime: String?,
        @SerializedName("device_title")
        val deviceTitle: String?,
        @SerializedName("device_name")
        val deviceName: String?,
        @SerializedName("recent_reply_ids")
        val recentReplyIds: String?,
        @SerializedName("recent_like_list")
        val recentLikeList: String?,
        val entityId: String?,
        val userAvatar: String?,
        val infoHtml: String?,
        val title: String?,
        val commentStatusText: String?,
        @SerializedName("comment_status")
        val commentStatus: Int?,
        val picArr: List<String>?,
        var replyRows: List<Data>?,
        val replyRowsMore: Int?,
        val logo: String?,
        @SerializedName("hot_num")
        val hotNum: String?,
        @SerializedName("feed_comment_num")
        val feedCommentNum: String?,
        @SerializedName("hot_num_txt")
        val hotNumTxt: String?,
        @SerializedName("feed_comment_num_txt")
        val feedCommentNumTxt: String?,
        @SerializedName("commentnum_txt")
        val commentnumTxt: String?,
        val commentCount: String?,
        @SerializedName("alias_title")
        val aliasTitle: String?,
        val userAction: UserAction?,
        val userInfo: UserInfo?,
        val fUserInfo: UserInfo?,
        var isFollow: Int?,
    ) : Parcelable

    @Parcelize
    data class Feed(
        val id: String? = null,
        val uid: String? = null,
        val username: String? = null,
        val message: String? = null,
        val pic: String? = null,
        val url: String? = null,
    ) : Parcelable

    @Parcelize
    data class ForwardSourceFeed(
        val entityType: String?,
        val feedType: String?,
        val id: String?,
        val username: String?,
        val uid: String?,
        val url: String?,
        val message: String?,
        @SerializedName("message_title")
        val messageTitle: String?,
        val pic: String?,
        val picArr: List<String>?,
    ) : Parcelable

    @Parcelize
    data class Vote(
        val id: String?,
        val type: Int?,
        @SerializedName("start_time")
        val startTime: Long?,
        @SerializedName("end_time")
        val endTime: Long?,
        @SerializedName("total_vote_num")
        val totalVoteNum: Int?,
        @SerializedName("total_comment_num")
        val totalCommentNum: Int?,
        @SerializedName("total_option_num")
        val totalOptionNum: Int?,
        @SerializedName("max_select_num")
        val maxSelectNum: Int?,
        @SerializedName("min_select_num")
        val minSelectNum: Int?,
        @SerializedName("message_title")
        val messageTitle: String?,
        val options: List<Option>?,
    ) : Parcelable

    @Parcelize
    data class Option(
        @SerializedName("total_select_num")
        val totalSelectNum: Long?,
        val id: String?,
        @SerializedName("vote_id")
        val voteId: String?,
        val title: String?,
        val status: Int?,
        val order: Int?,
        val color: String?,
    ) : Parcelable

    @Parcelize
    data class RelationRows(
        val id: String?,
        val logo: String?,
        val title: String?,
        val url: String?,
        val entityType: String?,
    ) : Parcelable

    @Parcelize
    data class TargetRow(
        val id: String?,
        val logo: String?,
        val title: String?,
        val url: String?,
        val entityType: String?,
        val targetType: String?,
    ) : Parcelable

    @Parcelize
    data class ExtraDataArr(
        val pageTitle: String?,
        val cardPageName: String?,
    ) : Parcelable

    @Parcelize
    data class UserInfo(
        val uid: String?,
        val username: String?,
        val level: Int?,
        val logintime: Long?,
        val regdate: String?,
        val entityType: String?,
        val displayUsername: String?,
        val userAvatar: String?,
        val cover: String?,
        val fans: String?,
        val follow: String?,
        val bio: String?,
    ) : Parcelable

    @Parcelize
    data class TabList(
        val title: String?,
        val url: String?,
        @SerializedName("page_name")
        val pageName: String?,
        val entityType: String?,
        val entityId: Int?,
    ) : Parcelable

    @Parcelize
    data class HomeTabCardRows(
        val entityType: String?,
        val entityTemplate: String?,
        val title: String?,
        val url: String?,
        val entities: List<Entities>?,
        val entityId: String?,
    ) : Parcelable

    @Parcelize
    data class UserAction(
        var like: Int?,
        //val favorite: Int?,
        var follow: Int? = 0,
        //val collect: Int?,
        //var followAuthor: Int?,
        //val authorFollowYou: Int?
    ) : Parcelable

    data class ReplyRows(
        val id: String?,
        val uid: String?,
        val feedUid: String?,
        val username: String?,
        var message: String?,
        val ruid: String?,
        val rusername: String?,
        val picArr: List<String>?,
        val pic: String?,
        val userInfo: UserInfo?,
    )

    @Parcelize
    data class Entities(
        val uid: String?,
        val userAvatar: String?,
        @SerializedName("device_title")
        val deviceTitle: String?,
        val dateline: String?,
        val username: String?,
        val url: String?,
        val pic: String?,
        val title: String?,
        val message: String?,
        val logo: String?,
        val id: String?,
        val entityType: String?,
        @SerializedName("alias_title")
        val aliasTitle: String?,
        val userInfo: UserInfo?,
    ) : Parcelable

}



================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/HomeMenu.kt
================================================
package com.example.c001apk.compose.logic.model

import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity
data class HomeMenu(
    var position: Int,
    @PrimaryKey
    var title: String,
    var isEnable: Boolean
)

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/LikeAdapter.kt
================================================
package com.example.c001apk.compose.logic.model

import com.google.gson.Gson
import com.google.gson.TypeAdapter
import com.google.gson.TypeAdapterFactory
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import java.io.IOException

object LikeAdapterFactory : TypeAdapterFactory {
    override fun <T> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T> {
        return LikeAdapter(gson) as TypeAdapter<T>
    }
}

class LikeAdapter(private val gson: Gson) : TypeAdapter<LikeResponse.Data?>() {
    @Throws(IOException::class)
    override fun write(jsonWriter: JsonWriter, feed: LikeResponse.Data?) {
        throw RuntimeException("Not implemented")
    }

    @Throws(IOException::class)
    override fun read(jsonReader: JsonReader): LikeResponse.Data? {
        return when (jsonReader.peek()) {
            JsonToken.NUMBER -> LikeResponse.Data(count = jsonReader.nextInt().toString())

            JsonToken.STRING -> LikeResponse.Data(count = jsonReader.nextString())

            JsonToken.BEGIN_OBJECT ->
                gson.fromJson(jsonReader, LikeResponse.Data::class.java)

            else -> throw RuntimeException("Expected object or int, not " + jsonReader.peek())
        }
    }
}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/LikeResponse.kt
================================================
package com.example.c001apk.compose.logic.model

import com.google.gson.annotations.JsonAdapter

data class LikeResponse(
    @JsonAdapter(LikeAdapterFactory::class)
    val data: Data?,
    val status: Int?,
    val error: Int?,
    val message: String?,
    val messageStatus: String?,
) {
    data class Data(
        val count: String?,
        val follow: Int? = 0,
    )
}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/LoadUrlResponse.kt
================================================
package com.example.c001apk.compose.logic.model

data class LoadUrlResponse(
    val status: Int?,
    val error: Int?,
    val message: String?,
    val data: Data?
) {
    data class Data(
        val title: String,
        val logo: String?,
        val url: String,
        val description: String,
    )
}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/LoginResponse.kt
================================================
package com.example.c001apk.compose.logic.model

data class LoginResponse(
    val status: Int?,
    val messageStatus: Int?,
    val message: String?,
    val uid: String?,
    val username: String?,
    val token: String?,
    val refreshToken: String?
)


================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/MessageListResponse.kt
================================================
package com.example.c001apk.compose.logic.model

import com.google.gson.annotations.SerializedName

data class MessageListResponse(
    val status: Int?,
    val message: String?,
    val messageStatus: String?,
    val data: List<Data>?
) {
    data class Data(
        val title: String?,
        val id: String?,
        val ukey: String?,
        val uid: String?,
        val username: String?,
        val fromuid: String?,
        val fromusername: String?,
        val islast: Int?,
        val isnew: Int?,
        val message: String?,
        @SerializedName("message_pic")
        val messagePic: String?,
        val dateline: Long?,
        val entityType: String?,
        val entityId: String?,
        val messageUid: String?,
        val messageUsername: String?,
        val userAvatar: String?,
        val fromUserAvatar: String?,
        val messageUserAvatar: String?,
        var unreadNum: Int?,
        @SerializedName("is_top")
        val isTop: Int?,
        val entityTemplate: String?,
    )
}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/OSSUploadPrepareModel.kt
================================================
package com.example.c001apk.compose.logic.model


data class OSSUploadPrepareModel(
    val name: String,
    val resolution: String,
    val md5: String,
)

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/OSSUploadPrepareResponse.kt
================================================
package com.example.c001apk.compose.logic.model

data class OSSUploadPrepareResponse(
    val status: Int?,
    val error: Int?,
    val message: String?,
    val messageStatus: String?,
    val data: Data?
) {
    data class Data(
        val fileInfo: List<FileInfo>,
        val uploadPrepareInfo: UploadPrepareInfo
    )

    data class FileInfo(
        val name: String,
        val resolution: String,
        val md5: String,
        val url: String,
        val uploadFileName: String
    )

    data class UploadPrepareInfo(
        val accessKeySecret: String,
        val accessKeyId: String,
        val securityToken: String,
        val expiration: String,
        val uploadImagePrefix: String,
        val endPoint: String,
        val bucket: String,
        val callbackUrl: String,
    )
}


================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/PostReplyResponse.kt
================================================
package com.example.c001apk.compose.logic.model

class PostReplyResponse(
    val status: Int?,
    val message: String?,
    val messageStatus: String?,
    val data: TotalReplyResponse.Data?
)

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/RecentAtUser.kt
================================================
package com.example.c001apk.compose.logic.model

import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity
data class RecentAtUser(
    var id: Long = System.currentTimeMillis(),
    val group: String = "recent",
    val avatar: String,
    @PrimaryKey(autoGenerate = false)
    val username: String,
)

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/StringEntity.kt
================================================
package com.example.c001apk.compose.logic.model

import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity
data class StringEntity(
    @PrimaryKey(autoGenerate = false)
    var data: String,
    var id: Long = System.currentTimeMillis()
)

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/TopicBean.kt
================================================
package com.example.c001apk.compose.logic.model



data class TopicBean(
    val url: String,
    val title: String
)

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/TotalReplyResponse.kt
================================================
package com.example.c001apk.compose.logic.model


import com.google.gson.annotations.SerializedName

data class TotalReplyResponse(
    val status: Int?,
    val error: Int?,
    val message: String?,
    val data: List<Data>?
) {

    data class Data(
        var lastupdate: Long?,
        @SerializedName("extra_key") val extraKey: String?,
        val entityType: String?,
        val id: String,
        val ruid: String?,
        val uid: String,
        val feedUid: String?,
        var username: String,
        val rusername: String?,
        var message: String,
        val pic: String?,
        val picArr: List<String>?,
        val dateline: Long,
        var likenum: String,
        val replynum: String,
        val userAvatar: String,
        var replyRows: MutableList<Data>?,
        val replyRowsMore: Int?,
        val userAction: UserAction?,
        val userInfo: UserInfo
    )

    data class UserAction(var like: Int)

    data class UserInfo(val username: String)

}



================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/UpdateCheckItem.kt
================================================
package com.example.c001apk.compose.logic.model

import android.os.Parcelable
import kotlinx.parcelize.Parcelize

/**
 * Created by bggRGjQaUbCoE on 2024/6/12
 */
@Parcelize
data class UpdateCheckItem(
    val key: String,
    val value: String,
) : Parcelable

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/model/UpdateCheckResponse.kt
================================================
package com.example.c001apk.compose.logic.model



data class UpdateCheckResponse(val data: List<Data>) {
    data class Data(
        val id: Int,
        val title: String,
        val shorttitle: String,
        val logo: String,
        val apkversionname: String,
        val apkversioncode: Long,
        val apksize: String,
        val lastupdate: Long,
        val packageName: String,
        val changelog: String,
        val pkg_bit_type: Int,
        var localVersionName: String?,
        var localVersionCode: Long?,
        var expand: Boolean = false,
    )

}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/network/ApiService.kt
================================================
package com.example.c001apk.compose.logic.network

import com.example.c001apk.compose.constant.Constants.EMPTY_STRING
import com.example.c001apk.compose.logic.model.CheckCountResponse
import com.example.c001apk.compose.logic.model.CheckResponse
import com.example.c001apk.compose.logic.model.CreateFeedResponse
import com.example.c001apk.compose.logic.model.FeedContentResponse
import com.example.c001apk.compose.logic.model.HomeFeedResponse
import com.example.c001apk.compose.logic.model.LikeResponse
import com.example.c001apk.compose.logic.model.LoadUrlResponse
import com.example.c001apk.compose.logic.model.OSSUploadPrepareResponse
import com.example.c001apk.compose.logic.model.TotalReplyResponse
import okhttp3.MultipartBody
import okhttp3.ResponseBody
import retrofit2.Call
import retrofit2.http.FieldMap
import retrofit2.http.FormUrlEncoded
import retrofit2.http.GET
import retrofit2.http.Multipart
import retrofit2.http.POST
import retrofit2.http.Part
import retrofit2.http.Query
import retrofit2.http.Url

/**
 * Created by bggRGjQaUbCoE on 2024/6/3
 */
interface ApiService {

    @GET("/v6/main/indexV8")
    fun getHomeFeed(
        @Query("page") page: Int,
        @Query("firstLaunch") firstLaunch: Int,
        @Query("installTime") installTime: String,
        @Query("firstItem") firstItem: String?,
        @Query("lastItem") lastItem: String?,
        @Query("ids") ids: String = EMPTY_STRING,
    ): Call<HomeFeedResponse>

    @GET
    fun getFeedContent(
        @Url url: String,
    ): Call<FeedContentResponse>

    @GET("/v6/feed/replyList")
    fun getFeedContentReply(
        @Query("id") id: String,
        @Query("listType") listType: String,
        @Query("page") page: Int,
        @Query("firstItem") firstItem: String?,
        @Query("lastItem") lastItem: String?,
        @Query("discussMode") discussMode: Int,
        @Query("feedType") feedType: String,
        @Query("blockStatus") blockStatus: Int,
        @Query("fromFeedAuthor") fromFeedAuthor: Int
    ): Call<HomeFeedResponse>

    @GET("/v6/search")
    fun getSearch(
        @Query("type") type: String,
        @Query("feedType") feedType: String,
        @Query("sort") sort: String,
        @Query("searchValue") keyWord: String,
        @Query("pageType") pageType: String?,
        @Query("pageParam") pageParam: String?,
        @Query("page") page: Int,
        @Query("lastItem") lastItem: String?,
        @Query("showAnonymous") showAnonymous: Int = -1
    ): Call<HomeFeedResponse>

    @GET("/v6/feed/replyList?listType=&discussMode=0&feedType=feed_reply&blockStatus=0&fromFeedAuthor=0")
    fun getReply2Reply(
        @Query("id") id: String,
        @Query("page") page: Int,
        @Query("lastItem") lastItem: String?
    ): Call<HomeFeedResponse>

    @GET("/v6/user/space")
    fun getUserSpace(
        @Query("uid") uid: String,
    ): Call<FeedContentResponse>

    @GET("/v6/user/feedList?showAnonymous=0&isIncludeTop=1&showDoing=0")
    fun getUserFeed(
        @Query("uid") uid: String,
        @Query("page") page: Int,
        @Query("lastItem") lastItem: String?
    ): Call<HomeFeedResponse>

    @GET("/v6/apk/detail")
    fun getAppInfo(
        @Query("id") id: String,
        @Query("installed") installed: Int = 1,
    ): Call<FeedContentResponse>

    @POST("/v6/apk/download?extra=")
    fun getAppDownloadLink(
        @Query("pn") id: String,
        @Query("aid") aid: String,
        @Query("vc") vc: String,
    ): Call<Any>

    @Multipart
    @POST("/v6/apk/checkUpdate?coolmarket_beta=0")
    fun getAppsUpdate(
        @Part pkgs: MultipartBody.Part
    ): Call<HomeFeedResponse>

    @GET //("/v6/topic/newTagDetail")
    fun getTopicLayout(
        @Url url: String,
        @Query("tag") tag: String?, // topic
        @Query("id") id: String? // product
    ): Call<FeedContentResponse>

    @GET("/v6/product/detail")
    fun getProductLayout(
        @Query("id") id: String
    ): Call<FeedContentResponse>

    @GET("/v6/user/profile")
    fun getProfile(
        @Query("uid") uid: String
    ): Call<FeedContentResponse>

    @GET
    fun getFollowList(
        @Url url: String,
        @Query("uid") uid: String?,
        @Query("id") id: String?,
        @Query("showDefault") showDefault: Int?,
        @Query("page") page: Int,
        @Query("lastItem") lastItem: String?
    ): Call<HomeFeedResponse>

    @POST
    fun postLike(
        @Url url: String,
        @Query("id") id: String
    ): Call<LikeResponse>

    @GET("/v6/account/checkLoginInfo")
    fun checkLoginInfo(
    ): Call<CheckResponse>

    @GET
    fun getLoginParam(
        @Url url: String
    ): Call<ResponseBody>

    @POST("/auth/loginByCoolApk")
    @FormUrlEncoded
    fun tryLogin(@FieldMap data: HashMap<String, String?>): Call<ResponseBody>

    @GET
    fun getCaptcha(@Url url: String): Call<ResponseBody>

    @GET
    fun getValidateCaptcha(@Url url: String): Call<ResponseBody>

    @POST("v6/feed/reply")
    @FormUrlEncoded
    fun postReply(
        @FieldMap data: HashMap<String, String>,
        @Query("id") id: String,
        @Query("type") type: String
    ): Call<FeedContentResponse>

    @GET("/v6/page/dataList")
    fun getDataList(
        @Query("url") url: String,
        @Query("title") title: String,
        @Query("subTitle") subTitle: String?,
        @Query("lastItem") lastItem: String?,
        @Query("page") page: Int
    ): Call<HomeFeedResponse>

    @GET("/v6/dyhArticle/list")
    fun getDyhDetail(
        @Query("dyhId") dyhId: String,
        @Query("type") type: String,
        @Query("page") page: Int,
        @Query("lastItem") lastItem: String?
    ): Call<HomeFeedResponse>

    @GET("/v6/picture/list")
    fun getCoolPic(
        @Query("tag") tag: String,
        @Query("type") type: String,
        @Query("page") page: Int,
        @Query("lastItem") lastItem: String?
    ): Call<HomeFeedResponse>


    @GET("/auth/login")
    fun getSmsLoginParam(
        @Query("type") type: String = "mobile",
    ): Call<ResponseBody>

    @POST("/auth/login")
    @FormUrlEncoded
    fun getSmsToken(
        @Query("type") type: String = "mobile",
        @FieldMap data: HashMap<String, String?>
    ): Call<ResponseBody>

    @GET
    fun getMessage(
        @Url url: String,
        @Query("page") page: Int,
        @Query("lastItem") lastItem: String?
    ): Call<HomeFeedResponse>

    @POST
    fun postFollowUnFollow(
        @Url url: String,
        @Query("uid") uid: String
    ): Call<LikeResponse>

    @POST("/v6/feed/createFeed")
    @FormUrlEncoded
    fun postCreateFeed(
        @FieldMap data: HashMap<String, String>
    ): Call<CreateFeedResponse>

    @POST("/v6/account/requestValidate")
    @FormUrlEncoded
    fun postRequestValidate(
        @FieldMap data: HashMap<String, String?>
    ): Call<LikeResponse>

    @GET("/v6/vote/commentList")
    fun getVoteComment(
        @Query("fid") fid: String,
        @Query("extra_key") extraKey: String,
        @Query("page") page: Int,
        @Query("firstItem") firstItem: String?,
        @Query("lastItem") lastItem: String?,
    ): Call<TotalReplyResponse>

    @GET("/v6/question/answerList")
    fun getAnswerList(
        @Query("id") fid: String,
        @Query("sort") sort: String,
        @Query("page") page: Int,
        @Query("firstItem") firstItem: String?,
        @Query("lastItem") lastItem: String?,
    ): Call<TotalReplyResponse>

    @GET
    fun getProductList(
        @Url url: String
    ): Call<HomeFeedResponse>

    @GET
    fun getCollectionList(
        @Url url: String,
        @Query("uid") uid: String?,
        @Query("id") id: String?,
        @Query("showDefault") showDefault: Int,
        @Query("page") page: Int,
        @Query("lastItem") lastItem: String?
    ): Call<HomeFeedResponse>

    @POST
    fun postDelete(
        @Url url: String,
        @Query("id") id: String,
    ): Call<LikeResponse>

    @POST("/v6/product/changeFollowStatus")
    @FormUrlEncoded
    fun postFollow(
        @FieldMap data: HashMap<String, String>
    ): Call<LikeResponse>

    @GET
    fun getFollow(
        @Url url: String,
        @Query("tag") tag: String?,
        @Query("id") id: String?,
    ): Call<LikeResponse>

    @POST("/v6/upload/ossUploadPrepare")
    @FormUrlEncoded
    fun postOSSUploadPrepare(
        @FieldMap data: HashMap<String, String>
    ): Call<OSSUploadPrepareResponse>

    @GET("/v6/feed/searchTag")
    fun getSearchTag(
        @Query("q") query: String,
        @Query("page") page: Int,
        @Query("recentIds") recentIds: String?,
        @Query("firstItem") firstItem: String?,
        @Query("lastItem") lastItem: String?,
    ): Call<HomeFeedResponse>

    @GET("/v6/feed/loadShareUrl")
    fun loadShareUrl(
        @Query("url") url: String,
        @Query("packageName") packageName: String = EMPTY_STRING,
    ): Call<LoadUrlResponse>

    @GET
    fun messageOperation(
        @Url url: String,
        @Query("ukey") ukey: String?,
        @Query("uid") uid: String?,
        @Query("page") page: Int?,
        @Query("firstItem") firstItem: String?,
        @Query("lastItem") lastItem: String?,
    ): Call<HomeFeedResponse>

    @Multipart
    @POST("/v6/message/send")
    fun sendMessage(
        @Query("uid") uid: String,
        @Part message: MultipartBody.Part,
        @Part pic: MultipartBody.Part
    ): Call<HomeFeedResponse>

    @GET
    fun deleteMessage(
        @Url url: String,
        @Query("ukey") ukey: String?,
        @Query("id") uid: String?,
    ): Call<LikeResponse>

    @GET("/v6/message/showImage")
    fun getImageUrl(
        @Query("id") id: String,
        @Query("type") type: String = "s",
    ): Call<Any>

    @GET("/v6/notification/checkCount")
    fun checkCount(): Call<CheckCountResponse>

    @POST
    @FormUrlEncoded
    fun postDelete(
        @Url url: String,
        @FieldMap data: Map<String, String>?
    ): Call<LikeResponse>
}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/providable/LocalUserPreferences.kt
================================================
package com.example.c001apk.compose.logic.providable

import androidx.compose.runtime.staticCompositionLocalOf
import com.example.c001apk.compose.logic.datastore.UserPreferencesCompat

val LocalUserPreferences = staticCompositionLocalOf { UserPreferencesCompat.default() }


================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/repository/BlackListRepo.kt
================================================
package com.example.c001apk.compose.logic.repository

import androidx.lifecycle.LiveData
import com.example.c001apk.compose.di.TopicBlackList
import com.example.c001apk.compose.di.UserBlackList
import com.example.c001apk.compose.logic.dao.StringEntityDao
import com.example.c001apk.compose.logic.model.StringEntity
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.withContext
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class BlackListRepo @Inject constructor(
    @UserBlackList
    private val userBlackListDao: StringEntityDao,
    @TopicBlackList
    private val topicBlackListDao: StringEntityDao,
) {

    fun loadAllUserListLive(): LiveData<List<StringEntity>> {
        return userBlackListDao.loadAllListLive()
    }

    fun loadAllUserListFlow(): Flow<List<StringEntity>> {
        return userBlackListDao.loadAllListFlow()
    }

    suspend fun insertUid(uid: String) {
        userBlackListDao.insert(StringEntity(uid))
    }

    suspend fun insertUidList(list: List<StringEntity>) {
        userBlackListDao.insertList(list)
    }

    suspend fun checkUid(uid: String): Boolean {
        return userBlackListDao.isExist(uid)
    }

    suspend fun saveUid(uid: String) {
        if (!userBlackListDao.isExist(uid)) {
            userBlackListDao.insert(StringEntity(uid))
        }
    }

    suspend fun deleteUid(uid: String) {
        userBlackListDao.delete(uid)
    }

    suspend fun deleteAllUser() {
        userBlackListDao.deleteAll()
    }

    fun loadAllTopicListLive(): LiveData<List<StringEntity>> {
        return topicBlackListDao.loadAllListLive()
    }

    fun loadAllTopicListFlow(): Flow<List<StringEntity>> {
        return topicBlackListDao.loadAllListFlow()
    }

    suspend fun insertTopic(topic: String) {
        topicBlackListDao.insert(StringEntity(topic))
    }

    suspend fun insertTopicList(list: List<StringEntity>) {
        topicBlackListDao.insertList(list)
    }

    suspend fun checkTopic(topic: String): Boolean {
        return withContext(Dispatchers.IO) {
            topicBlackListDao.isContain(topic)
        }
    }

    suspend fun saveTopic(topic: String) {
        if (!topicBlackListDao.isExist(topic)) {
            topicBlackListDao.insert(StringEntity(topic))
        }
    }

    suspend fun deleteTopic(topic: String) {
        topicBlackListDao.delete(topic)
    }

    suspend fun deleteAllTopic() {
        topicBlackListDao.deleteAll()
    }

}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/repository/HistoryFavoriteRepo.kt
================================================
package com.example.c001apk.compose.logic.repository

import androidx.lifecycle.LiveData
import com.example.c001apk.compose.di.BrowseHistory
import com.example.c001apk.compose.di.FeedFavorite
import com.example.c001apk.compose.logic.dao.HistoryFavoriteDao
import com.example.c001apk.compose.logic.model.FeedEntity
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class HistoryFavoriteRepo @Inject constructor(
    @BrowseHistory
    private val browseHistoryDao: HistoryFavoriteDao,
    @FeedFavorite
    private val feedFavoriteDao: HistoryFavoriteDao,
) {

    fun loadAllHistoryListLive(): LiveData<List<FeedEntity>> {
        return browseHistoryDao.loadAllListLive()
    }

    fun loadAllHistoryListFlow(): Flow<List<FeedEntity>> {
        return browseHistoryDao.loadAllListFlow()
    }

    suspend fun insertHistory(history: FeedEntity) {
        browseHistoryDao.insert(history)
    }

    suspend fun checkHistory(id: String): Boolean {
        return browseHistoryDao.isExist(id)
    }

    suspend fun saveHistory(
        id: String,
        uid: String,
        uname: String,
        avatar: String,
        device: String,
        message: String,
        pubDate: String
    ) {
        if (!browseHistoryDao.isExist(id))
            browseHistoryDao.insert(
                FeedEntity(
                    id,
                    uid,
                    uname,
                    avatar,
                    device,
                    message,
                    pubDate
                )
            )
    }

    suspend fun deleteHistory(id: String) {
        browseHistoryDao.delete(id)
    }

    suspend fun deleteAllHistory() {
        browseHistoryDao.deleteAll()
    }

    fun loadAllFavoriteListLive(): LiveData<List<FeedEntity>> {
        return feedFavoriteDao.loadAllListLive()
    }

    fun loadAllFavoriteListFlow(): Flow<List<FeedEntity>> {
        return feedFavoriteDao.loadAllListFlow()
    }

    suspend fun insertFavorite(favorite: FeedEntity) {
        feedFavoriteDao.insert(favorite)
    }

    suspend fun checkFavorite(id: String): Boolean {
        return feedFavoriteDao.isExist(id)
    }

    suspend fun saveFavorite(
        id: String,
        uid: String,
        uname: String,
        avatar: String,
        device: String,
        message: String,
        pubDate: String
    ) {
        if (!feedFavoriteDao.isExist(id))
            feedFavoriteDao.insert(
                FeedEntity(
                    id,
                    uid,
                    uname,
                    avatar,
                    device,
                    message,
                    pubDate
                )
            )
    }

    suspend fun deleteFavorite(id: String) {
        feedFavoriteDao.delete(id)
    }

    suspend fun deleteAllFavorite() {
        feedFavoriteDao.deleteAll()
    }

    suspend fun deleteHistoryByUid(uid: String){
        browseHistoryDao.deleteByUid(uid)
    }
    
    suspend fun deleteFavByUid(uid: String){
        feedFavoriteDao.deleteByUid(uid)
    }

}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/repository/HomeMenuRepo.kt
================================================
package com.example.c001apk.compose.logic.repository

import androidx.lifecycle.LiveData
import com.example.c001apk.compose.logic.dao.HomeMenuDao
import com.example.c001apk.compose.logic.model.HomeMenu
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class HomeMenuRepo @Inject constructor(
    private val homeMenuDao: HomeMenuDao,
) {

    fun loadAllListLive(): LiveData<List<HomeMenu>> {
        return homeMenuDao.loadAllListLive()
    }

    suspend fun insert(homeMenu: HomeMenu) {
        homeMenuDao.insert(homeMenu)
    }

    suspend fun insertList(list: List<HomeMenu>) {
        homeMenuDao.insertList(list)
    }

    suspend fun updateList(list: List<HomeMenu>) {
        homeMenuDao.updateList(list)
    }

    suspend fun deleteAll() {
        homeMenuDao.deleteAll()
    }

}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/repository/NetworkRepo.kt
================================================
package com.example.c001apk.compose.logic.repository

import com.example.c001apk.compose.constant.Constants.LOADING_FAILED
import com.example.c001apk.compose.di.AccountService
import com.example.c001apk.compose.di.Api1Service
import com.example.c001apk.compose.di.Api1ServiceNoRedirect
import com.example.c001apk.compose.di.Api2Service
import com.example.c001apk.compose.logic.model.FeedContentResponse
import com.example.c001apk.compose.logic.model.HomeFeedResponse
import com.example.c001apk.compose.logic.network.ApiService
import com.example.c001apk.compose.logic.state.LoadingState
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import okhttp3.MultipartBody
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine

/**
 * Created by bggRGjQaUbCoE on 2024/6/3
 */
@Singleton
class NetworkRepo @Inject constructor(
    @Api1Service
    private val apiService: ApiService,
    @Api1ServiceNoRedirect
    private val apiServiceNoRedirect: ApiService,
    @Api2Service
    private val api2Service: ApiService,
    @AccountService
    private val accountService: ApiService,
) {

    suspend fun getHomeFeed(
        page: Int,
        firstLaunch: Int,
        installTime: String,
        firstItem: String?,
        lastItem: String?
    ) = flowList {
        api2Service.getHomeFeed(page, firstLaunch, installTime, firstItem, lastItem).await()
    }

    suspend fun getFeedContent(url: String) = flowData {
        apiService.getFeedContent(url).await()
    }

    suspend fun getFeedContentReply(
        id: String,
        listType: String,
        page: Int,
        firstItem: String?,
        lastItem: String?,
        discussMode: Int,
        feedType: String,
        blockStatus: Int,
        fromFeedAuthor: Int
    ) = flowList {
        api2Service.getFeedContentReply(
            id,
            listType,
            page,
            firstItem,
            lastItem,
            discussMode,
            feedType,
            blockStatus,
            fromFeedAuthor
        ).await()
    }

    suspend fun getSearch(
        type: String, feedType: String, sort: String, keyWord: String, pageType: String?,
        pageParam: String?, page: Int, lastItem: String?
    ) = flowList {
        apiService.getSearch(
            type, feedType, sort, keyWord, pageType, pageParam, page, lastItem
        ).await()
    }

    suspend fun getReply2Reply(id: String, page: Int, lastItem: String?) = flowList {
        apiService.getReply2Reply(id, page, lastItem).await()
    }

    suspend fun getTopicLayout(url: String, tag: String?, id: String?) = flowData {
        api2Service.getTopicLayout(url, tag, id).await()
    }

    suspend fun getProductLayout(id: String) = fire {
        Result.success(apiService.getProductLayout(id).await())
    }

    suspend fun getUserSpace(uid: String) = flowData {
        apiService.getUserSpace(uid).await()
    }

    suspend fun getUserFeed(uid: String, page: Int, lastItem: String?) = flowList {
        apiService.getUserFeed(uid, page, lastItem).await()
    }

    suspend fun getAppInfo(id: String) = flowData {
        apiService.getAppInfo(id).await()
    }

    suspend fun getAppDownloadLink(pn: String, aid: String, vc: String) = fire {
        val appResponse = apiServiceNoRedirect.getAppDownloadLink(pn, aid, vc).response()
        Result.success(appResponse.headers()["Location"])
    }

    suspend fun getAppsUpdate(pkgs: String) = flowList {
        val multipartBody = MultipartBody.Part.createFormData("pkgs", pkgs)
        apiService.getAppsUpdate(multipartBody).await()
    }

    suspend fun getProfile(uid: String) = fire {
        Result.success(api2Service.getProfile(uid).await())
    }

    suspend fun getFollowList(
        url: String,
        uid: String?,
        id: String?,
        showDefault: Int?,
        page: Int,
        lastItem: String?
    ) = flowList {
        apiService.getFollowList(url, uid, id, showDefault, page, lastItem).await()
    }

    suspend fun postLike(url: String, id: String) = fire {
        Result.success(apiService.postLike(url, id).await())
    }

    suspend fun checkLoginInfo() = fire {
        Result.success(apiService.checkLoginInfo().response())
    }

    suspend fun getLoginParam(url: String) = fire {
        Result.success(accountService.getLoginParam(url).response())
    }

    suspend fun tryLogin(data: HashMap<String, String?>) = fire {
        Result.success(accountService.tryLogin(data).response())
    }

    suspend fun getCaptcha(url: String) = fire {
        Result.success(accountService.getCaptcha(url).response())
    }

    suspend fun getValidateCaptcha(url: String) = fire {
        Result.success(apiService.getValidateCaptcha(url).response())
    }

    suspend fun postReply(data: HashMap<String, String>, id: String, type: String) = fire {
        Result.success(apiService.postReply(data, id, type).await())
    }

    suspend fun getDataList(
        url: String, title: String, subTitle: String?, lastItem: String?, page: Int
    ) = flowList {
        api2Service.getDataList(url, title, subTitle, lastItem, page).await()
    }

    suspend fun getDyhDetail(dyhId: String, type: String, page: Int, lastItem: String?) =
        flowList {
            apiService.getDyhDetail(dyhId, type, page, lastItem).await()
        }

    suspend fun getCoolPic(tag: String, type: String, page: Int, lastItem: String?) =
        flowList {
            apiService.getCoolPic(tag, type, page, lastItem).await()
        }

    suspend fun getMessage(url: String, page: Int, lastItem: String?) = flowList {
        apiService.getMessage(url, page, lastItem).await()
    }

    suspend fun postFollowUnFollow(url: String, uid: String) = fire {
        Result.success(apiService.postFollowUnFollow(url, uid).await())
    }

    suspend fun postCreateFeed(data: HashMap<String, String>) = fire {
        Result.success(apiService.postCreateFeed(data).await())
    }

    suspend fun postRequestValidate(data: HashMap<String, String?>) = fire {
        Result.success(apiService.postRequestValidate(data).await())
    }

    suspend fun getVoteComment(
        fid: String,
        extraKey: String,
        page: Int,
        firstItem: String?,
        lastItem: String?,
    ) = fire {
        Result.success(apiService.getVoteComment(fid, extraKey, page, firstItem, lastItem).await())
    }

    suspend fun getAnswerList(
        id: String,
        sort: String,
        page: Int,
        firstItem: String?,
        lastItem: String?,
    ) = fire {
        Result.success(apiService.getAnswerList(id, sort, page, firstItem, lastItem).await())
    }

    suspend fun getProductList(url: String) = flowList {
        apiService.getProductList(url).await()
    }

    suspend fun getCollectionList(
        url: String,
        uid: String?,
        id: String?,
        showDefault: Int,
        page: Int,
        lastItem: String?
    ) = fire {
        Result.success(
            apiService.getCollectionList(url, uid, id, showDefault, page, lastItem).await()
        )
    }

    suspend fun postDelete(url: String, id: String) = fire {
        Result.success(apiService.postDelete(url, id).await())
    }

    suspend fun postFollow(data: HashMap<String, String>) = fire {
        Result.success(apiService.postFollow(data).await())
    }

    suspend fun getFollow(url: String, tag: String?, id: String?) = fire {
        Result.success(apiService.getFollow(url, tag, id).await())
    }

    suspend fun postOSSUploadPrepare(data: HashMap<String, String>) = fire {
        Result.success(apiService.postOSSUploadPrepare(data).await())
    }

    suspend fun getSearchTag(
        query: String,
        page: Int,
        recentIds: String?,
        firstItem: String?,
        lastItem: String?,
    ) = fire {
        Result.success(apiService.getSearchTag(query, page, recentIds, firstItem, lastItem).await())
    }

    suspend fun loadShareUrl(url: String) = fire {
        Result.success(apiService.loadShareUrl(url).await())
    }

    suspend fun messageOperation(
        url: String,
        ukey: String?,
        uid: String?,
        page: Int?,
        firstItem: String?,
        lastItem: String?,
    ) = flowList {
        apiService.messageOperation(url, ukey, uid, page, firstItem, lastItem).await()
    }

    suspend fun sendMessage(uid: String, message: MultipartBody.Part, pic: MultipartBody.Part) =
        fire {
            Result.success(apiService.sendMessage(uid, message, pic).await())
        }

    suspend fun deleteMessage(url: String, ukey: String, id: String?) = fire {
        Result.success(apiService.deleteMessage(url, ukey, id).await())
    }

    suspend fun getImageUrl(id: String) = fire {
        val response = apiServiceNoRedirect.getImageUrl(id).response()
        Result.success(response.headers()["Location"])
    }

    suspend fun checkCount() = fire {
        Result.success(apiService.checkCount().await())
    }


    suspend fun postDelete(url: String, data: Map<String, String>?) = fire {
        Result.success(apiService.postDelete(url, data).await())
    }

    private suspend fun <T> Call<T>.await(): T {
        return suspendCoroutine { continuation ->
            enqueue(object : Callback<T> {
                override fun onResponse(call: Call<T>, response: Response<T>) {
                    val body = response.body()
                    if (body != null) continuation.resume(body)
                    else continuation.resumeWithException(
                        RuntimeException("response body is null")
                    )
                }

                override fun onFailure(call: Call<T>, t: Throwable) {
                    continuation.resumeWithException(t)
                }
            })
        }
    }

    private suspend fun <T> Call<T>.response(): Response<T> {
        return suspendCoroutine { continuation ->
            enqueue(object : Callback<T> {
                override fun onResponse(call: Call<T>, response: Response<T>) {
                    continuation.resume(response)
                }

                override fun onFailure(call: Call<T>, t: Throwable) {
                    continuation.resumeWithException(t)
                }
            })
        }
    }

    private fun <T> fire(block: suspend () -> Result<T>) = flow {
        val result = try {
            block()
        } catch (e: Exception) {
            Result.failure(e)
        }
        emit(result)
    }.flowOn(Dispatchers.IO)

    private fun flowList(block: suspend () -> HomeFeedResponse) = flow {
        val result = try {
            val response = block()
            if (!response.message.isNullOrEmpty()) {
                LoadingState.Error(response.message)
            } else if (!response.data.isNullOrEmpty()) {
                LoadingState.Success(response.data)
            } else if (response.data?.isEmpty() == true) {
                LoadingState.Empty
            } else {
                LoadingState.Error(LOADING_FAILED)
            }
        } catch (e: Exception) {
            LoadingState.Error(e.message ?: "unknown error")
        }
        emit(result)
    }.flowOn(Dispatchers.IO)

    private fun flowData(block: suspend () -> FeedContentResponse) = flow {
        val result = try {
            val response = block()
            if (!response.message.isNullOrEmpty()) {
                LoadingState.Error(response.message)
            } else if (response.data != null) {
                LoadingState.Success(response.data)
            } else {
                LoadingState.Error(LOADING_FAILED)
            }
        } catch (e: Exception) {
            LoadingState.Error(e.message ?: "unknown error")
        }
        emit(result)
    }.flowOn(Dispatchers.IO)

}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/repository/RecentAtUserRepo.kt
================================================
package com.example.c001apk.compose.logic.repository

import androidx.lifecycle.LiveData
import com.example.c001apk.compose.logic.dao.RecentAtUserDao
import com.example.c001apk.compose.logic.model.RecentAtUser
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class RecentAtUserRepo @Inject constructor(
    private val recentAtUserDao: RecentAtUserDao,
) {

    fun loadAllListLive(): LiveData<List<RecentAtUser>> {
        return recentAtUserDao.loadAllListLive()
    }

    suspend fun insertUser(user: RecentAtUser) {
        recentAtUserDao.insert(user)
    }

    suspend fun insertList(list: List<RecentAtUser>) {
        recentAtUserDao.insertList(list)
    }

    suspend fun deleteUser(user: String) {
        recentAtUserDao.delete(user)
    }

    suspend fun deleteUser(user: RecentAtUser) {
        recentAtUserDao.delete(user)
    }

    suspend fun deleteAll() {
        recentAtUserDao.deleteAll()
    }

    suspend fun checkUser(username: String): Boolean {
        return recentAtUserDao.isExist(username)
    }

    suspend fun updateUser(username: String, newId: Long) {
        recentAtUserDao.updateUser(username, newId)
    }

}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/repository/RecentEmojiRepo.kt
================================================
package com.example.c001apk.compose.logic.repository

import androidx.lifecycle.LiveData
import com.example.c001apk.compose.di.RecentEmoji
import com.example.c001apk.compose.logic.dao.StringEntityDao
import com.example.c001apk.compose.logic.model.StringEntity
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class RecentEmojiRepo @Inject constructor(
    @RecentEmoji
    private val recentEmojiDao: StringEntityDao,
) {

    fun loadAllListLive(): LiveData<List<StringEntity>> {
        return recentEmojiDao.loadAllListLive()
    }

    fun loadAllListFlow(): Flow<List<StringEntity>> {
        return recentEmojiDao.loadAllListFlow()
    }

    suspend fun insertEmoji(emoji: StringEntity) {
        recentEmojiDao.insert(emoji)
    }

    suspend fun insertList(list: List<StringEntity>) {
        recentEmojiDao.insertList(list)
    }

    suspend fun saveEmoji(emoji: String) {
        if (!recentEmojiDao.isExist(emoji)) {
            recentEmojiDao.insert(StringEntity(emoji))
        }
    }

    suspend fun deleteEmoji(emoji: String) {
        recentEmojiDao.delete(emoji)
    }

    suspend fun deleteEmoji(emoji: StringEntity) {
        recentEmojiDao.delete(emoji)
    }

    suspend fun deleteAll() {
        recentEmojiDao.deleteAll()
    }

    suspend fun checkEmoji(emoji: String): Boolean {
        return recentEmojiDao.isExist(emoji)
    }

    suspend fun updateEmoji(data: String) {
        recentEmojiDao.updateHistory(data, System.currentTimeMillis())
    }

    suspend fun updateEmoji(oldData: String, newData: String) {
        recentEmojiDao.updateEmoji(oldData, newData, System.currentTimeMillis())
    }

}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/repository/SearchHistoryRepo.kt
================================================
package com.example.c001apk.compose.logic.repository

import androidx.lifecycle.LiveData
import com.example.c001apk.compose.di.SearchHistory
import com.example.c001apk.compose.logic.dao.StringEntityDao
import com.example.c001apk.compose.logic.model.StringEntity
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class SearchHistoryRepo @Inject constructor(
    @SearchHistory
    private val searchHistoryDao: StringEntityDao,
) {

    fun loadAllListFlow(): Flow<List<StringEntity>> {
        return searchHistoryDao.loadAllListFlow()
    }

    fun loadAllListLive(): LiveData<List<StringEntity>> {
        return searchHistoryDao.loadAllListLive()
    }

    suspend fun insertHistory(history: StringEntity) {
        searchHistoryDao.insert(history)
    }

    suspend fun insertList(list: List<StringEntity>) {
        searchHistoryDao.insertList(list)
    }

    suspend fun saveHistory(history: String) {
        searchHistoryDao.insert(StringEntity(history))
    }

    suspend fun deleteHistory(history: String) {
        searchHistoryDao.delete(history)
    }

    suspend fun deleteAllHistory() {
        searchHistoryDao.deleteAll()
    }

    suspend fun isExist(history: String): Boolean {
        return searchHistoryDao.isExist(history)
    }

    suspend fun updateHistory(data: String) {
        searchHistoryDao.updateHistory(data, System.currentTimeMillis())
    }

}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/repository/UserPreferencesRepository.kt
================================================
package com.example.c001apk.compose.logic.repository

import com.example.c001apk.compose.FollowType
import com.example.c001apk.compose.ThemeMode
import com.example.c001apk.compose.ThemeType
import com.example.c001apk.compose.logic.datastore.UserPreferencesDataSource
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class UserPreferencesRepository @Inject constructor(
    private val userPreferencesDataSource: UserPreferencesDataSource
) {
    val data get() = userPreferencesDataSource.data

    suspend fun setThemeMode(value: ThemeMode) = userPreferencesDataSource.setThemeMode(value)

    suspend fun setMaterialYou(value: Boolean) = userPreferencesDataSource.setMaterialYou(value)

    suspend fun setPureBlack(value: Boolean) = userPreferencesDataSource.setPureBlack(value)

    suspend fun setFontScale(value: Float) = userPreferencesDataSource.setFontScale(value)

    suspend fun setContentScale(value: Float) = userPreferencesDataSource.setContentScale(value)

    suspend fun setSZLMId(value: String) = userPreferencesDataSource.setSZLMId(value)

    suspend fun setImageQuality(value: Int) = userPreferencesDataSource.setImageQuality(value)

    suspend fun setImageFilter(value: Boolean) = userPreferencesDataSource.setImageFilter(value)

    suspend fun setOpenInBrowser(value: Boolean) = userPreferencesDataSource.setOpenInBrowser(value)

    suspend fun setShowSquare(value: Boolean) = userPreferencesDataSource.setShowSquare(value)

    suspend fun setRecordHistory(value: Boolean) = userPreferencesDataSource.setRecordHistory(value)

    suspend fun setShowEmoji(value: Boolean) = userPreferencesDataSource.setShowEmoji(value)

    suspend fun setCheckUpdate(value: Boolean) = userPreferencesDataSource.setCheckUpdate(value)

    suspend fun setCheckCount(value: Boolean) = userPreferencesDataSource.setCheckCount(value)

    suspend fun setVersionName(value: String) = userPreferencesDataSource.setVersionName(value)

    suspend fun setApiVersion(value: String) = userPreferencesDataSource.setApiVersion(value)

    suspend fun setVersionCode(value: String) = userPreferencesDataSource.setVersionCode(value)

    suspend fun setManufacturer(value: String) = userPreferencesDataSource.setManufacturer(value)

    suspend fun setBrand(value: String) = userPreferencesDataSource.setBrand(value)

    suspend fun setModel(value: String) = userPreferencesDataSource.setModel(value)

    suspend fun setBuildNumber(value: String) = userPreferencesDataSource.setBuildNumber(value)

    suspend fun setSdkInt(value: String) = userPreferencesDataSource.setSdkInt(value)

    suspend fun setAndroidVersion(value: String) =
        userPreferencesDataSource.setAndroidVersion(value)

    suspend fun setUserAgent(value: String) = userPreferencesDataSource.setUserAgent(value)

    suspend fun setXAppDevice(value: String) = userPreferencesDataSource.setXAppDevice(value)

    suspend fun setXAppToken(value: String) = userPreferencesDataSource.setXAppToken(value)

    suspend fun setIsLogin(value: Boolean) = userPreferencesDataSource.setIsLogin(value)

    suspend fun setUserAvatar(value: String) = userPreferencesDataSource.setUserAvatar(value)

    suspend fun setUsername(value: String) = userPreferencesDataSource.setUsername(value)

    suspend fun setLevel(value: String) = userPreferencesDataSource.setLevel(value)

    suspend fun setExperience(value: String) = userPreferencesDataSource.setExperience(value)

    suspend fun setNextLevelExperience(value: String) =
        userPreferencesDataSource.setNextLevelExperience(value)

    suspend fun setUid(value: String) = userPreferencesDataSource.setUid(value)

    suspend fun setToken(value: String) = userPreferencesDataSource.setToken(value)

    suspend fun setFollowType(value: FollowType) = userPreferencesDataSource.setFollowType(value)

    suspend fun setRecentIds(value: String) = userPreferencesDataSource.setRecentIds(value)

    suspend fun setCheckCountPeriod(value: Int) =
        userPreferencesDataSource.setCheckCountPeriod(value)

    suspend fun setInstallTime(value: String) = userPreferencesDataSource.setInstallTime(value)

    suspend fun setThemeType(value: ThemeType) = userPreferencesDataSource.setThemeType(value)

    suspend fun setSeedColor(value: String) = userPreferencesDataSource.setSeedColor(value)

    suspend fun setPaletteStyle(value: Int) = userPreferencesDataSource.setPaletteStyle(value)

}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/state/FooterState.kt
================================================
package com.example.c001apk.compose.logic.state

/**
 * Created by bggRGjQaUbCoE on 2024/6/3
 */
sealed class FooterState : State(){
    data object Loading : FooterState()
    data object End : FooterState()
    data object Success : FooterState()
    data class Error(val errMsg: String) : FooterState()
}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/state/LoadingState.kt
================================================
package com.example.c001apk.compose.logic.state

/**
 * Created by bggRGjQaUbCoE on 2024/6/3
 */
sealed class LoadingState<out T> : State() {
    data object Loading : LoadingState<Nothing>()
    data object Empty : LoadingState<Nothing>()
    data class Success<out T>(val response: T) : LoadingState<T>()
    data class Error(val errMsg: String) : LoadingState<Nothing>()
}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/logic/state/State.kt
================================================
package com.example.c001apk.compose.logic.state

/**
 * Created by bggRGjQaUbCoE on 2024/6/3
 */
sealed class State


================================================
FILE: app/src/main/java/com/example/c001apk/compose/ui/app/AppContentScreen.kt
================================================
package com.example.c001apk.compose.ui.app

import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.only
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import androidx.hilt.navigation.compose.hiltViewModel
import com.example.c001apk.compose.ui.component.CommonScreen
import com.example.c001apk.compose.util.ReportType
import com.example.c001apk.compose.util.makeToast

/**
 * Created by bggRGjQaUbCoE on 2024/6/10
 */
@Composable
fun AppContentScreen(
    refreshState: Boolean,
    resetRefreshState: () -> Unit,
    id: String,
    appCommentSort: String,
    appCommentTitle: String,
    onViewUser: (String) -> Unit,
    onViewFeed: (String, Boolean) -> Unit,
    onOpenLink: (String, String?) -> Unit,
    onCopyText: (String?) -> Unit,
    onReport: (String, ReportType) -> Unit,
    isScrollingUp: ((Boolean) -> Unit)? = null,
) {

    val viewModel =
        hiltViewModel<AppContentViewModel, AppContentViewModel.ViewModelFactory>(key = id + appCommentSort) { factory ->
            factory.create(
                url = "/page?url=/feed/apkCommentList?id=$id$appCommentSort",
                appCommentTitle = appCommentTitle
            )
        }

    val windowInsets =
        WindowInsets.navigationBars.only(WindowInsetsSides.Start + WindowInsetsSides.Bottom)

    CommonScreen(
        viewModel = viewModel,
        refreshState = refreshState,
        resetRefreshState = resetRefreshState,
        paddingValues = windowInsets.asPaddingValues(),
        onViewUser = onViewUser,
        onViewFeed = onViewFeed,
        onOpenLink = onOpenLink,
        onCopyText = onCopyText,
        onReport = onReport,
        isScrollingUp = isScrollingUp,
    )

    val context = LocalContext.current
    viewModel.toastText?.let {
        viewModel.resetToastText()
        context.makeToast(it)
    }

}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/ui/app/AppContentViewModel.kt
================================================
package com.example.c001apk.compose.ui.app

import com.example.c001apk.compose.logic.model.HomeFeedResponse
import com.example.c001apk.compose.logic.repository.BlackListRepo
import com.example.c001apk.compose.logic.repository.NetworkRepo
import com.example.c001apk.compose.ui.base.BaseViewModel
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.lifecycle.HiltViewModel

/**
 * Created by bggRGjQaUbCoE on 2024/6/10
 */
@HiltViewModel(assistedFactory = AppContentViewModel.ViewModelFactory::class)
class AppContentViewModel @AssistedInject constructor(
    @Assisted("url") val url: String,
    @Assisted("appCommentTitle") val appCommentTitle: String,
    networkRepo: NetworkRepo,
    blackListRepo: BlackListRepo,
) : BaseViewModel(networkRepo, blackListRepo) {

    @AssistedFactory
    interface ViewModelFactory {
        fun create(
            @Assisted("url") url: String,
            @Assisted("appCommentTitle") appCommentTitle: String,
        ): AppContentViewModel
    }

    init {
        fetchData()
    }

    override suspend fun customFetchData() =
        networkRepo.getDataList(
            url,
            appCommentTitle,
            null,
            lastItem,
            page
        )

    override fun handleLoadMore(response: List<HomeFeedResponse.Data>): List<HomeFeedResponse.Data> {
        return response.distinctBy { it.entityId }
    }

}

================================================
FILE: app/src/main/java/com/example/c001apk/compose/ui/app/AppScreen.kt
================================================
package com.example.c001apk.compose.ui.app

import android.content.Intent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.SecondaryTabRow
import androidx.compose.material3.Tab
import androidx.compose.material3.TabRowDefaults
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.core.app.ActivityOptionsCompat
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import androidx.hilt.navigation.compose.hiltViewModel
import com.example.c001apk.compose.R
import com.example.c001apk.compose.constant.Constants.EMPTY_STRING
import com.example.c001apk.compose.logic.state.LoadingState
import com.example.c001apk.compose.ui.component.BackButton
import com.example.c001apk.compose.ui.component.cards.AppInfoCard
import com.example.c001apk.compose.ui.component.cards.LoadingCard
import com.example.c001apk.compose.ui.feed.reply.ReplyActivity
import com.example.c001apk.compose.util.CookieUtil.isLogin
import com.example.c001apk.compose.util.ReportType
import com.example.c001apk.compose.util.downloadApk
import com.example.c001apk.compose.util.makeToast
import com.google.accompanist.drawablepainter.rememberDrawablePainter
import kotlinx.coroutines.launch
import me.onebone.toolbar.CollapsingToolbarScaffold
import me.onebone.toolbar.ExperimentalToolbarApi
import me.onebone.toolbar.ScrollStrategy
import me.onebone.toolbar.rememberCollapsingToolbarScaffoldState

/**
 * Created by bggRGjQaUbCoE on 2024/6/10
 */
@OptIn(ExperimentalMaterial3Api::class, ExperimentalToolbarApi::class)
@Composable
fun AppScreen(
    onBackClick: () -> Unit,
    packageName: String,
    onViewUser: (String) -> Unit,
    onViewFeed: (String, Boolean) -> Unit,
    onOpenLink: (String, String?) -> Unit,
    onCopyText: (String?) -> Unit,
    onSearch: (String, String, String) -> Unit,
    onReport: (String, ReportType) -> Unit,
) {

    val viewModel =
        hiltViewModel<AppViewModel, AppViewModel.ViewModelFactory>(key = packageName) { factory ->
            factory.create(packageName)
        }

    val context = LocalContext.current

    val tabList by lazy { listOf("最近回复", "最新发布", "热度排序") }
    var dropdownMenuExpanded by remember { mutableStateOf(false) }

    val pagerState = rememberPagerState(
        initialPage = 0,
        pageCount = {
            tabList.size
        }
    )
    val scope = rememberCoroutineScope()
    var refreshState by remember { mutableStateOf(false) }

    val state = rememberCollapsingToolbarScaffoldState()

    val windowInsets = WindowInsets.systemBars
    var isScrollingUp by remember { mutableStateOf(false) }

    CollapsingToolbarScaffold(
        state = state,
        scrollStrategy = ScrollStrategy.ExitUntilCollapsed,
        modifier = Modifier.fillMaxSize(),
        toolbar = {
            TopAppBar(
                windowInsets = WindowInsets.systemBars
                    .only(WindowInsetsSides.Start + WindowInsetsSides.Top),
                navigationIcon = {
                    BackButton { onBackClick() }
                },
                title = {
                    Text(
                        modifier = Modifier
                            .graphicsLayer {
                                alpha = if (state.toolbarState.progress == 0f) 1f else 0f
                            },
                        text = viewModel.title,
                        maxLines = 1,
                        overflow = TextOverflow.Ellipsis
                    )
                },
                actions = {
                    if (viewModel.appState is LoadingState.Success) {
                        Row(Modifier.wrapContentSize(Alignment.TopEnd)) {
                            IconButton(
                                onClick = {
                                    onSearch(viewModel.title, "apk", viewModel.id)
                                }
                            ) {
                                Icon(Icons.Default.Search, contentDescription = null)
                            }
                            Box {
                                IconButton(onClick = { dropdownMenuExpanded = true }) {
                                    Icon(
                                        Icons.Default.MoreVert,
                                        contentDescription = null
                                    )
                                }
                                DropdownMenu(
                                    expanded = dropdownMenuExpanded,
                                    onDismissRequest = { dropdownMenuExpanded = false }
                                ) {
                                    if (isLogin) {
                                        DropdownMenuItem(
                                            text = {
                                                Text(
                                                    if (viewModel.isFollowed) "UnFollow"
                                                    else "Follow"
                                                )
                                            },
                                            onClick = {
                                                dropdownMenuExpanded = false
                                                viewModel.onGetFollowApk()
                                            }
                                        )
                                    }
                                    DropdownMenuItem(
                                        text = {
                                            Text(
                                                if (viewModel.isBlocked) "UnBlock"
                                                else "Block"
                                            )
                                        },
                                        onClick = {
                                            dropdownMenuExpanded = false
                                            viewModel.blockApp()
                                        }
                                    )
                                }
                            }

                        }
                    }
                },
                colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent),
            )
            if (viewModel.appState !is LoadingState.Error) {
                AppInfoCard(
                    modifier = Modifier
        
Download .txt
gitextract_r5thwsnn/

├── .gitignore
├── LICENSE
├── README.md
├── app/
│   ├── .gitignore
│   ├── build.gradle.kts
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── example/
│       │               └── c001apk/
│       │                   └── compose/
│       │                       └── ExampleInstrumentedTest.kt
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── assets/
│       │   │   └── devicemodel.txt
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── example/
│       │   │           └── c001apk/
│       │   │               └── compose/
│       │   │                   ├── C001Application.kt
│       │   │                   ├── constant/
│       │   │                   │   └── Constants.kt
│       │   │                   ├── di/
│       │   │                   │   ├── DataStoreModule.kt
│       │   │                   │   ├── DatabaseModule.kt
│       │   │                   │   └── NetworkModule.kt
│       │   │                   ├── logic/
│       │   │                   │   ├── dao/
│       │   │                   │   │   ├── HistoryFavoriteDao.kt
│       │   │                   │   │   ├── HomeMenuDao.kt
│       │   │                   │   │   ├── RecentAtUserDao.kt
│       │   │                   │   │   └── StringEntityDao.kt
│       │   │                   │   ├── database/
│       │   │                   │   │   ├── HistoryFavoriteDatabase.kt
│       │   │                   │   │   ├── HomeMenuDatabase.kt
│       │   │                   │   │   ├── RecentAtUserDatabase.kt
│       │   │                   │   │   └── StringEntityDatabase.kt
│       │   │                   │   ├── datastore/
│       │   │                   │   │   ├── UserPreferencesCompat.kt
│       │   │                   │   │   ├── UserPreferencesDataSource.kt
│       │   │                   │   │   └── UserPreferencesSerializer.kt
│       │   │                   │   ├── model/
│       │   │                   │   │   ├── AppItem.kt
│       │   │                   │   │   ├── CheckCountResponse.kt
│       │   │                   │   │   ├── CheckResponse.kt
│       │   │                   │   │   ├── CreateFeedResponse.kt
│       │   │                   │   │   ├── DeviceInfo.kt
│       │   │                   │   │   ├── FeedAdapter.kt
│       │   │                   │   │   ├── FeedArticleContentBean.kt
│       │   │                   │   │   ├── FeedContentResponse.kt
│       │   │                   │   │   ├── FeedEntity.kt
│       │   │                   │   │   ├── HomeFeedResponse.kt
│       │   │                   │   │   ├── HomeMenu.kt
│       │   │                   │   │   ├── LikeAdapter.kt
│       │   │                   │   │   ├── LikeResponse.kt
│       │   │                   │   │   ├── LoadUrlResponse.kt
│       │   │                   │   │   ├── LoginResponse.kt
│       │   │                   │   │   ├── MessageListResponse.kt
│       │   │                   │   │   ├── OSSUploadPrepareModel.kt
│       │   │                   │   │   ├── OSSUploadPrepareResponse.kt
│       │   │                   │   │   ├── PostReplyResponse.kt
│       │   │                   │   │   ├── RecentAtUser.kt
│       │   │                   │   │   ├── StringEntity.kt
│       │   │                   │   │   ├── TopicBean.kt
│       │   │                   │   │   ├── TotalReplyResponse.kt
│       │   │                   │   │   ├── UpdateCheckItem.kt
│       │   │                   │   │   └── UpdateCheckResponse.kt
│       │   │                   │   ├── network/
│       │   │                   │   │   └── ApiService.kt
│       │   │                   │   ├── providable/
│       │   │                   │   │   └── LocalUserPreferences.kt
│       │   │                   │   ├── repository/
│       │   │                   │   │   ├── BlackListRepo.kt
│       │   │                   │   │   ├── HistoryFavoriteRepo.kt
│       │   │                   │   │   ├── HomeMenuRepo.kt
│       │   │                   │   │   ├── NetworkRepo.kt
│       │   │                   │   │   ├── RecentAtUserRepo.kt
│       │   │                   │   │   ├── RecentEmojiRepo.kt
│       │   │                   │   │   ├── SearchHistoryRepo.kt
│       │   │                   │   │   └── UserPreferencesRepository.kt
│       │   │                   │   └── state/
│       │   │                   │       ├── FooterState.kt
│       │   │                   │       ├── LoadingState.kt
│       │   │                   │       └── State.kt
│       │   │                   ├── ui/
│       │   │                   │   ├── app/
│       │   │                   │   │   ├── AppContentScreen.kt
│       │   │                   │   │   ├── AppContentViewModel.kt
│       │   │                   │   │   ├── AppScreen.kt
│       │   │                   │   │   └── AppViewModel.kt
│       │   │                   │   ├── appupdate/
│       │   │                   │   │   └── AppUpdateScreen.kt
│       │   │                   │   ├── base/
│       │   │                   │   │   ├── BaseViewModel.kt
│       │   │                   │   │   └── PrefsViewModel.kt
│       │   │                   │   ├── blacklist/
│       │   │                   │   │   ├── BlackListScreen.kt
│       │   │                   │   │   └── BlackListViewModel.kt
│       │   │                   │   ├── carousel/
│       │   │                   │   │   ├── CarouselContentScreen.kt
│       │   │                   │   │   ├── CarouselScreen.kt
│       │   │                   │   │   └── CarouselViewModel.kt
│       │   │                   │   ├── chat/
│       │   │                   │   │   ├── ChatScreen.kt
│       │   │                   │   │   └── ChatViewModel.kt
│       │   │                   │   ├── collection/
│       │   │                   │   │   ├── CollectionScreen.kt
│       │   │                   │   │   └── CollectionViewModel.kt
│       │   │                   │   ├── component/
│       │   │                   │   │   ├── ArticleItem.kt
│       │   │                   │   │   ├── Button.kt
│       │   │                   │   │   ├── ChatEditText.kt
│       │   │                   │   │   ├── CoilLoader.kt
│       │   │                   │   │   ├── CommonScreen.kt
│       │   │                   │   │   ├── FooterCard.kt
│       │   │                   │   │   ├── IconText.kt
│       │   │                   │   │   ├── ImageView.kt
│       │   │                   │   │   ├── ItemCard.kt
│       │   │                   │   │   ├── LinkText.kt
│       │   │                   │   │   ├── NineImageView.kt
│       │   │                   │   │   ├── Transitions.kt
│       │   │                   │   │   ├── WebView.kt
│       │   │                   │   │   ├── cards/
│       │   │                   │   │   │   ├── AppCard.kt
│       │   │                   │   │   │   ├── AppInfoCard.kt
│       │   │                   │   │   │   ├── AppUpdateCard.kt
│       │   │                   │   │   │   ├── CardIndicator.kt
│       │   │                   │   │   │   ├── CarouselCard.kt
│       │   │                   │   │   │   ├── ChatLeftCard.kt
│       │   │                   │   │   │   ├── ChatRightCard.kt
│       │   │                   │   │   │   ├── ChatTimeCard.kt
│       │   │                   │   │   │   ├── CollectionCard.kt
│       │   │                   │   │   │   ├── FeedArticleCard.kt
│       │   │                   │   │   │   ├── FeedCard.kt
│       │   │                   │   │   │   ├── FeedReplyCard.kt
│       │   │                   │   │   │   ├── FeedReplySortCard.kt
│       │   │                   │   │   │   ├── HistoryCard.kt
│       │   │                   │   │   │   ├── IconLinkGridCard.kt
│       │   │                   │   │   │   ├── IconMiniGridCard.kt
│       │   │                   │   │   │   ├── IconMiniScrollCard.kt
│       │   │                   │   │   │   ├── IconScrollCard.kt
│       │   │                   │   │   │   ├── ImageSquareScrollCard.kt
│       │   │                   │   │   │   ├── ImageTextScrollCard.kt
│       │   │                   │   │   │   ├── LoadingCard.kt
│       │   │                   │   │   │   ├── MessageCard.kt
│       │   │                   │   │   │   ├── MessageFFFCard.kt
│       │   │                   │   │   │   ├── MessageHeaderCard.kt
│       │   │                   │   │   │   ├── MessageListCard.kt
│       │   │                   │   │   │   ├── MessageWidgetCard.kt
│       │   │                   │   │   │   ├── NotificationCard.kt
│       │   │                   │   │   │   ├── SearchHistoryCard.kt
│       │   │                   │   │   │   ├── TextCard.kt
│       │   │                   │   │   │   ├── TitleCard.kt
│       │   │                   │   │   │   └── UserInfoCard.kt
│       │   │                   │   │   ├── icons/
│       │   │                   │   │   │   └── Swatch.kt
│       │   │                   │   │   └── settings/
│       │   │                   │   │       ├── BasicListItem.kt
│       │   │                   │   │       ├── DropdownListItem.kt
│       │   │                   │   │       ├── StateBasicListItem.kt
│       │   │                   │   │       ├── StateDropdownListItem.kt
│       │   │                   │   │       └── SwitchListItem.kt
│       │   │                   │   ├── coolpic/
│       │   │                   │   │   ├── CoolPicContentScreen.kt
│       │   │                   │   │   ├── CoolPicContentViewModel.kt
│       │   │                   │   │   └── CoolPicScreen.kt
│       │   │                   │   ├── dyh/
│       │   │                   │   │   ├── DyhContentScreen.kt
│       │   │                   │   │   ├── DyhContentViewModel.kt
│       │   │                   │   │   └── DyhScreen.kt
│       │   │                   │   ├── feed/
│       │   │                   │   │   ├── FeedScreen.kt
│       │   │                   │   │   ├── FeedViewModel.kt
│       │   │                   │   │   └── reply/
│       │   │                   │   │       ├── ReplyActivity.kt
│       │   │                   │   │       ├── ReplyViewModel.kt
│       │   │                   │   │       └── emoji/
│       │   │                   │   │           ├── EmojiChildPagerAdapter.kt
│       │   │                   │   │           ├── EmojiGridAdapter.kt
│       │   │                   │   │           └── EmojiPagerAdapter.kt
│       │   │                   │   ├── ffflist/
│       │   │                   │   │   ├── FFFContentScreen.kt
│       │   │                   │   │   ├── FFFContentViewModel.kt
│       │   │                   │   │   └── FFFListScreen.kt
│       │   │                   │   ├── history/
│       │   │                   │   │   ├── HistoryScreen.kt
│       │   │                   │   │   └── HistoryViewModel.kt
│       │   │                   │   ├── home/
│       │   │                   │   │   ├── HomeScreen.kt
│       │   │                   │   │   ├── app/
│       │   │                   │   │   │   ├── AppListScreen.kt
│       │   │                   │   │   │   └── AppListViewModel.kt
│       │   │                   │   │   ├── feed/
│       │   │                   │   │   │   ├── HomeFeedScreen.kt
│       │   │                   │   │   │   └── HomeFeedViewModel.kt
│       │   │                   │   │   └── topic/
│       │   │                   │   │       ├── HomeTopicScreen.kt
│       │   │                   │   │       └── HomeTopicViewModel.kt
│       │   │                   │   ├── login/
│       │   │                   │   │   ├── LoginScreen.kt
│       │   │                   │   │   └── LoginViewModel.kt
│       │   │                   │   ├── main/
│       │   │                   │   │   ├── MainActivity.kt
│       │   │                   │   │   ├── MainNavigation.kt
│       │   │                   │   │   ├── MainScreen.kt
│       │   │                   │   │   ├── MainViewModel.kt
│       │   │                   │   │   └── Router.kt
│       │   │                   │   ├── message/
│       │   │                   │   │   ├── MessageScreen.kt
│       │   │                   │   │   └── MessageViewModel.kt
│       │   │                   │   ├── notification/
│       │   │                   │   │   ├── NoticeScreen.kt
│       │   │                   │   │   └── NoticeViewModel.kt
│       │   │                   │   ├── others/
│       │   │                   │   │   └── CopyTextScreen.kt
│       │   │                   │   ├── search/
│       │   │                   │   │   ├── SearchContentScreen.kt
│       │   │                   │   │   ├── SearchContentViewModel.kt
│       │   │                   │   │   ├── SearchResultScreen.kt
│       │   │                   │   │   ├── SearchScreen.kt
│       │   │                   │   │   └── SearchViewModel.kt
│       │   │                   │   ├── settings/
│       │   │                   │   │   ├── AboutScreen.kt
│       │   │                   │   │   ├── LicenseScreen.kt
│       │   │                   │   │   ├── ParamsScreen.kt
│       │   │                   │   │   ├── SettingsScreen.kt
│       │   │                   │   │   └── SettingsViewModel.kt
│       │   │                   │   ├── theme/
│       │   │                   │   │   ├── Color.kt
│       │   │                   │   │   ├── Theme.kt
│       │   │                   │   │   └── Type.kt
│       │   │                   │   ├── topic/
│       │   │                   │   │   ├── TopicContentScreen.kt
│       │   │                   │   │   ├── TopicContentViewModel.kt
│       │   │                   │   │   ├── TopicScreen.kt
│       │   │                   │   │   └── TopicViewModel.kt
│       │   │                   │   ├── user/
│       │   │                   │   │   ├── UserScreen.kt
│       │   │                   │   │   └── UserViewModel.kt
│       │   │                   │   └── webview/
│       │   │                   │       ├── WebViewScreen.kt
│       │   │                   │       └── WebViewViewModel.kt
│       │   │                   ├── util/
│       │   │                   │   ├── AddCookiesInterceptor.kt
│       │   │                   │   ├── Base64Utils.kt
│       │   │                   │   ├── CacheDataManager.kt
│       │   │                   │   ├── CommentHelper.kt
│       │   │                   │   ├── CookieUtil.kt
│       │   │                   │   ├── DateUtils.kt
│       │   │                   │   ├── EmojiUtils.kt
│       │   │                   │   ├── Extensions.kt
│       │   │                   │   ├── ImageDownloadUtil.kt
│       │   │                   │   ├── ImageShowUtil.kt
│       │   │                   │   ├── LoginCookiesInterceptor.kt
│       │   │                   │   ├── NetWorkUtil.kt
│       │   │                   │   ├── OSSUtil.kt
│       │   │                   │   ├── OssUploadUtil.kt
│       │   │                   │   ├── SpannableStringBuilderUtil.kt
│       │   │                   │   ├── TokenDeviceUtils.kt
│       │   │                   │   └── Utils.kt
│       │   │                   └── view/
│       │   │                       ├── BadgeDrawable.kt
│       │   │                       ├── BadgedImageView.kt
│       │   │                       ├── CenteredImageSpan.kt
│       │   │                       ├── CircleIndexIndicator.kt
│       │   │                       ├── CircleIndicator.kt
│       │   │                       ├── LinkTextView.kt
│       │   │                       ├── MyURLSpan.kt
│       │   │                       ├── NestedScrollableHost.kt
│       │   │                       ├── NineGridImageView.kt
│       │   │                       ├── RoundedImageView.kt
│       │   │                       ├── SmoothInputLayout.kt
│       │   │                       └── circleindicator/
│       │   │                           ├── BaseCircleIndicator.kt
│       │   │                           ├── CircleIndicator3.kt
│       │   │                           └── Config.kt
│       │   ├── proto/
│       │   │   └── UserPreferences.proto
│       │   └── res/
│       │       ├── anim/
│       │       │   ├── anim_bottom_sheet_slide_down.xml
│       │       │   ├── anim_bottom_sheet_slide_up.xml
│       │       │   ├── indicator_animator.xml
│       │       │   ├── indicator_animator_reverse.xml
│       │       │   └── scale_with_alpha.xml
│       │       ├── color/
│       │       │   └── image_stroke.xml
│       │       ├── drawable/
│       │       │   ├── ic_author.xml
│       │       │   ├── ic_feed_top.xml
│       │       │   ├── ic_launcher_foreground.xml
│       │       │   ├── ic_photo.xml
│       │       │   ├── ic_subauthor.xml
│       │       │   ├── outline_alternate_email_24.xml
│       │       │   ├── outline_backspace_24.xml
│       │       │   ├── outline_emoji_emotions_24.xml
│       │       │   ├── outline_image_24.xml
│       │       │   ├── outline_keyboard_hide_24.xml
│       │       │   ├── outline_keyboard_show_24.xml
│       │       │   ├── outline_note_alt_24.xml
│       │       │   ├── outline_tag_24.xml
│       │       │   ├── round_corners_12.xml
│       │       │   ├── selector_bg_12_trans.xml
│       │       │   ├── selector_bg_trans.xml
│       │       │   ├── selector_emoji.xml
│       │       │   ├── selector_emoji_indicator.xml
│       │       │   ├── selector_emoji_indicator_selected.xml
│       │       │   ├── selector_reply.xml
│       │       │   ├── shape_oval_primary.xml
│       │       │   └── white_radius.xml
│       │       ├── layout/
│       │       │   ├── activity_reply.xml
│       │       │   ├── dialog_refresh.xml
│       │       │   ├── item_captcha.xml
│       │       │   ├── item_emoji.xml
│       │       │   └── item_emoji_child_viewpager.xml
│       │       ├── layout-land/
│       │       │   └── activity_reply.xml
│       │       ├── mipmap-anydpi-v26/
│       │       │   ├── ic_launcher.xml
│       │       │   └── ic_launcher_round.xml
│       │       ├── values/
│       │       │   ├── attrs.xml
│       │       │   ├── colors.xml
│       │       │   ├── strings.xml
│       │       │   └── themes.xml
│       │       ├── values-night/
│       │       │   └── colors.xml
│       │       ├── values-night-v31/
│       │       │   └── colors.xml
│       │       ├── values-v31/
│       │       │   └── colors.xml
│       │       └── xml/
│       │           ├── backup_rules.xml
│       │           ├── data_extraction_rules.xml
│       │           └── file_provider_paths.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── example/
│                       └── c001apk/
│                           └── compose/
│                               └── ExampleUnitTest.kt
├── build.gradle.kts
├── gradle/
│   ├── libs.versions.toml
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── renovate.json
└── settings.gradle.kts
Condensed preview — 275 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,273K chars).
[
  {
    "path": ".gitignore",
    "chars": 293,
    "preview": "*.iml\n.gradle\n/local.properties\n/.idea/caches\n/.idea/libraries\n/.idea/modules.xml\n/.idea/workspace.xml\n/.idea/navEditor."
  },
  {
    "path": "LICENSE",
    "chars": 34523,
    "preview": "                    GNU AFFERO GENERAL PUBLIC LICENSE\n                       Version 3, 19 November 2007\n\n Copyright (C)"
  },
  {
    "path": "README.md",
    "chars": 29,
    "preview": "# c001apk-compose\n\ntest only\n"
  },
  {
    "path": "app/.gitignore",
    "chars": 24,
    "preview": "/build\n/release\n/schemas"
  },
  {
    "path": "app/build.gradle.kts",
    "chars": 6327,
    "preview": "import com.android.build.gradle.internal.api.ApkVariantOutputImpl\nimport org.jetbrains.kotlin.konan.properties.Propertie"
  },
  {
    "path": "app/proguard-rules.pro",
    "chars": 6554,
    "preview": "-optimizationpasses 5\n\n# Keep DataStore fields\n-keepclassmembers class * extends com.google.protobuf.GeneratedMessageLit"
  },
  {
    "path": "app/src/androidTest/java/com/example/c001apk/compose/ExampleInstrumentedTest.kt",
    "chars": 690,
    "preview": "package com.example.c001apk.compose\n\nimport androidx.test.ext.junit.runners.AndroidJUnit4\nimport androidx.test.platform."
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "chars": 17605,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:to"
  },
  {
    "path": "app/src/main/assets/devicemodel.txt",
    "chars": 12533,
    "preview": "1503-M02\n1503-A01\n1505-A01\n1505-A02\n1603-A03\n1605-A01\n1605-A02\n1607-A01\n1801-A01\n1707-A01\n1713-A01\n1807-A01\n1809-A01\n180"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/C001Application.kt",
    "chars": 1141,
    "preview": "package com.example.c001apk.compose\n\nimport android.app.Application\nimport coil.Coil\nimport coil.ImageLoader\nimport com."
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/constant/Constants.kt",
    "chars": 2748,
    "preview": "package com.example.c001apk.compose.constant\n\nimport com.example.c001apk.compose.util.CookieUtil.isDarkMode\n\n/**\n * Crea"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/di/DataStoreModule.kt",
    "chars": 1015,
    "preview": "package com.example.c001apk.compose.di\n\nimport android.content.Context\nimport androidx.datastore.core.DataStore\nimport a"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/di/DatabaseModule.kt",
    "chars": 5634,
    "preview": "package com.example.c001apk.compose.di\n\nimport android.content.Context\nimport androidx.room.Room\nimport com.example.c001"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/di/NetworkModule.kt",
    "chars": 4797,
    "preview": "package com.example.c001apk.compose.di\n\nimport com.example.c001apk.compose.BuildConfig\nimport com.example.c001apk.compos"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/dao/HistoryFavoriteDao.kt",
    "chars": 1036,
    "preview": "package com.example.c001apk.compose.logic.dao\n\nimport androidx.lifecycle.LiveData\nimport androidx.room.Dao\nimport androi"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/dao/HomeMenuDao.kt",
    "chars": 1090,
    "preview": "package com.example.c001apk.compose.logic.dao\n\nimport androidx.lifecycle.LiveData\nimport androidx.room.Dao\nimport androi"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/dao/RecentAtUserDao.kt",
    "chars": 1473,
    "preview": "package com.example.c001apk.compose.logic.dao\n\nimport androidx.lifecycle.LiveData\nimport androidx.room.Dao\nimport androi"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/dao/StringEntityDao.kt",
    "chars": 1594,
    "preview": "package com.example.c001apk.compose.logic.dao\n\nimport androidx.lifecycle.LiveData\nimport androidx.room.Dao\nimport androi"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/database/HistoryFavoriteDatabase.kt",
    "chars": 412,
    "preview": "package com.example.c001apk.compose.logic.database\n\nimport androidx.room.Database\nimport androidx.room.RoomDatabase\nimpo"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/database/HomeMenuDatabase.kt",
    "chars": 379,
    "preview": "package com.example.c001apk.compose.logic.database\n\nimport androidx.room.Database\nimport androidx.room.RoomDatabase\nimpo"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/database/RecentAtUserDatabase.kt",
    "chars": 403,
    "preview": "package com.example.c001apk.compose.logic.database\n\nimport androidx.room.Database\nimport androidx.room.RoomDatabase\nimpo"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/database/StringEntityDatabase.kt",
    "chars": 403,
    "preview": "package com.example.c001apk.compose.logic.database\n\nimport androidx.room.Database\nimport androidx.room.RoomDatabase\nimpo"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/datastore/UserPreferencesCompat.kt",
    "chars": 6802,
    "preview": "package com.example.c001apk.compose.logic.datastore\n\nimport androidx.compose.foundation.isSystemInDarkTheme\nimport andro"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/datastore/UserPreferencesDataSource.kt",
    "chars": 6683,
    "preview": "package com.example.c001apk.compose.logic.datastore\n\nimport androidx.datastore.core.DataStore\nimport com.example.c001apk"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/datastore/UserPreferencesSerializer.kt",
    "chars": 892,
    "preview": "package com.example.c001apk.compose.logic.datastore\n\nimport androidx.datastore.core.CorruptionException\nimport androidx."
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/AppItem.kt",
    "chars": 165,
    "preview": "package com.example.c001apk.compose.logic.model\n\nimport android.content.pm.PackageInfo\n\ndata class AppItem(\n    var labe"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/CheckCountResponse.kt",
    "chars": 561,
    "preview": "package com.example.c001apk.compose.logic.model\n\nimport com.google.gson.annotations.SerializedName\n\ndata class CheckCoun"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/CheckResponse.kt",
    "chars": 886,
    "preview": "package com.example.c001apk.compose.logic.model\n\nimport com.google.gson.annotations.SerializedName\n\ndata class CheckResp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/CreateFeedResponse.kt",
    "chars": 656,
    "preview": "package com.example.c001apk.compose.logic.model\n\nimport com.google.gson.annotations.SerializedName\n\ndata class CreateFee"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/DeviceInfo.kt",
    "chars": 243,
    "preview": "package com.example.c001apk.compose.logic.model\n\ndata class DeviceInfo(\n    val deviceId: String,\n    val mac: String,\n "
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/FeedAdapter.kt",
    "chars": 1235,
    "preview": "package com.example.c001apk.compose.logic.model\n\nimport com.example.c001apk.compose.logic.model.HomeFeedResponse.Feed\nim"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/FeedArticleContentBean.kt",
    "chars": 335,
    "preview": "package com.example.c001apk.compose.logic.model\n\nimport java.util.UUID\n\ndata class FeedArticleContentBean(\n    val key: "
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/FeedContentResponse.kt",
    "chars": 312,
    "preview": "package com.example.c001apk.compose.logic.model\n\nimport android.os.Parcelable\nimport kotlinx.parcelize.Parcelize\n\n@Parce"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/FeedEntity.kt",
    "chars": 404,
    "preview": "package com.example.c001apk.compose.logic.model\n\nimport androidx.room.Entity\nimport androidx.room.PrimaryKey\n\n@Entity\nda"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/HomeFeedResponse.kt",
    "chars": 10935,
    "preview": "package com.example.c001apk.compose.logic.model\n\n\nimport android.os.Parcelable\nimport com.google.gson.annotations.JsonAd"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/HomeMenu.kt",
    "chars": 228,
    "preview": "package com.example.c001apk.compose.logic.model\n\nimport androidx.room.Entity\nimport androidx.room.PrimaryKey\n\n@Entity\nda"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/LikeAdapter.kt",
    "chars": 1318,
    "preview": "package com.example.c001apk.compose.logic.model\n\nimport com.google.gson.Gson\nimport com.google.gson.TypeAdapter\nimport c"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/LikeResponse.kt",
    "chars": 378,
    "preview": "package com.example.c001apk.compose.logic.model\n\nimport com.google.gson.annotations.JsonAdapter\n\ndata class LikeResponse"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/LoadUrlResponse.kt",
    "chars": 310,
    "preview": "package com.example.c001apk.compose.logic.model\n\ndata class LoadUrlResponse(\n    val status: Int?,\n    val error: Int?,\n"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/LoginResponse.kt",
    "chars": 257,
    "preview": "package com.example.c001apk.compose.logic.model\n\ndata class LoginResponse(\n    val status: Int?,\n    val messageStatus: "
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/MessageListResponse.kt",
    "chars": 1024,
    "preview": "package com.example.c001apk.compose.logic.model\n\nimport com.google.gson.annotations.SerializedName\n\ndata class MessageLi"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/OSSUploadPrepareModel.kt",
    "chars": 156,
    "preview": "package com.example.c001apk.compose.logic.model\n\n\ndata class OSSUploadPrepareModel(\n    val name: String,\n    val resolu"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/OSSUploadPrepareResponse.kt",
    "chars": 810,
    "preview": "package com.example.c001apk.compose.logic.model\n\ndata class OSSUploadPrepareResponse(\n    val status: Int?,\n    val erro"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/PostReplyResponse.kt",
    "chars": 194,
    "preview": "package com.example.c001apk.compose.logic.model\n\nclass PostReplyResponse(\n    val status: Int?,\n    val message: String?"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/RecentAtUser.kt",
    "chars": 313,
    "preview": "package com.example.c001apk.compose.logic.model\n\nimport androidx.room.Entity\nimport androidx.room.PrimaryKey\n\n@Entity\nda"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/StringEntity.kt",
    "chars": 250,
    "preview": "package com.example.c001apk.compose.logic.model\n\nimport androidx.room.Entity\nimport androidx.room.PrimaryKey\n\n@Entity\nda"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/TopicBean.kt",
    "chars": 117,
    "preview": "package com.example.c001apk.compose.logic.model\n\n\n\ndata class TopicBean(\n    val url: String,\n    val title: String\n)"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/TotalReplyResponse.kt",
    "chars": 997,
    "preview": "package com.example.c001apk.compose.logic.model\n\n\nimport com.google.gson.annotations.SerializedName\n\ndata class TotalRep"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/UpdateCheckItem.kt",
    "chars": 260,
    "preview": "package com.example.c001apk.compose.logic.model\n\nimport android.os.Parcelable\nimport kotlinx.parcelize.Parcelize\n\n/**\n *"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/model/UpdateCheckResponse.kt",
    "chars": 578,
    "preview": "package com.example.c001apk.compose.logic.model\n\n\n\ndata class UpdateCheckResponse(val data: List<Data>) {\n    data class"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/network/ApiService.kt",
    "chars": 9943,
    "preview": "package com.example.c001apk.compose.logic.network\n\nimport com.example.c001apk.compose.constant.Constants.EMPTY_STRING\nim"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/providable/LocalUserPreferences.kt",
    "chars": 273,
    "preview": "package com.example.c001apk.compose.logic.providable\n\nimport androidx.compose.runtime.staticCompositionLocalOf\nimport co"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/repository/BlackListRepo.kt",
    "chars": 2501,
    "preview": "package com.example.c001apk.compose.logic.repository\n\nimport androidx.lifecycle.LiveData\nimport com.example.c001apk.comp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/repository/HistoryFavoriteRepo.kt",
    "chars": 3096,
    "preview": "package com.example.c001apk.compose.logic.repository\n\nimport androidx.lifecycle.LiveData\nimport com.example.c001apk.comp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/repository/HomeMenuRepo.kt",
    "chars": 813,
    "preview": "package com.example.c001apk.compose.logic.repository\n\nimport androidx.lifecycle.LiveData\nimport com.example.c001apk.comp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/repository/NetworkRepo.kt",
    "chars": 12004,
    "preview": "package com.example.c001apk.compose.logic.repository\n\nimport com.example.c001apk.compose.constant.Constants.LOADING_FAIL"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/repository/RecentAtUserRepo.kt",
    "chars": 1172,
    "preview": "package com.example.c001apk.compose.logic.repository\n\nimport androidx.lifecycle.LiveData\nimport com.example.c001apk.comp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/repository/RecentEmojiRepo.kt",
    "chars": 1695,
    "preview": "package com.example.c001apk.compose.logic.repository\n\nimport androidx.lifecycle.LiveData\nimport com.example.c001apk.comp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/repository/SearchHistoryRepo.kt",
    "chars": 1442,
    "preview": "package com.example.c001apk.compose.logic.repository\n\nimport androidx.lifecycle.LiveData\nimport com.example.c001apk.comp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/repository/UserPreferencesRepository.kt",
    "chars": 4426,
    "preview": "package com.example.c001apk.compose.logic.repository\n\nimport com.example.c001apk.compose.FollowType\nimport com.example.c"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/state/FooterState.kt",
    "chars": 307,
    "preview": "package com.example.c001apk.compose.logic.state\n\n/**\n * Created by bggRGjQaUbCoE on 2024/6/3\n */\nsealed class FooterStat"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/state/LoadingState.kt",
    "chars": 375,
    "preview": "package com.example.c001apk.compose.logic.state\n\n/**\n * Created by bggRGjQaUbCoE on 2024/6/3\n */\nsealed class LoadingSta"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/logic/state/State.kt",
    "chars": 116,
    "preview": "package com.example.c001apk.compose.logic.state\n\n/**\n * Created by bggRGjQaUbCoE on 2024/6/3\n */\nsealed class State\n"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/app/AppContentScreen.kt",
    "chars": 2078,
    "preview": "package com.example.c001apk.compose.ui.app\n\nimport androidx.compose.foundation.layout.WindowInsets\nimport androidx.compo"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/app/AppContentViewModel.kt",
    "chars": 1462,
    "preview": "package com.example.c001apk.compose.ui.app\n\nimport com.example.c001apk.compose.logic.model.HomeFeedResponse\nimport com.e"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/app/AppScreen.kt",
    "chars": 15847,
    "preview": "package com.example.c001apk.compose.ui.app\n\nimport android.content.Intent\nimport androidx.compose.animation.AnimatedVisi"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/app/AppViewModel.kt",
    "chars": 5670,
    "preview": "package com.example.c001apk.compose.ui.app\n\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mut"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/appupdate/AppUpdateScreen.kt",
    "chars": 5637,
    "preview": "package com.example.c001apk.compose.ui.appupdate\n\nimport androidx.compose.foundation.layout.Arrangement\nimport androidx."
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/base/BaseViewModel.kt",
    "chars": 11590,
    "preview": "package com.example.c001apk.compose.ui.base\n\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mu"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/base/PrefsViewModel.kt",
    "chars": 2292,
    "preview": "package com.example.c001apk.compose.ui.base\n\nimport androidx.lifecycle.ViewModel\nimport androidx.lifecycle.viewModelScop"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/blacklist/BlackListScreen.kt",
    "chars": 14604,
    "preview": "package com.example.c001apk.compose.ui.blacklist\n\nimport androidx.activity.compose.rememberLauncherForActivityResult\nimp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/blacklist/BlackListViewModel.kt",
    "chars": 2882,
    "preview": "package com.example.c001apk.compose.ui.blacklist\n\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runti"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/carousel/CarouselContentScreen.kt",
    "chars": 1607,
    "preview": "package com.example.c001apk.compose.ui.carousel\n\nimport androidx.compose.foundation.layout.PaddingValues\nimport androidx"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/carousel/CarouselScreen.kt",
    "chars": 9218,
    "preview": "package com.example.c001apk.compose.ui.carousel\n\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.f"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/carousel/CarouselViewModel.kt",
    "chars": 2808,
    "preview": "package com.example.c001apk.compose.ui.carousel\n\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtim"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/chat/ChatScreen.kt",
    "chars": 29285,
    "preview": "package com.example.c001apk.compose.ui.chat\n\nimport androidx.activity.compose.rememberLauncherForActivityResult\nimport a"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/chat/ChatViewModel.kt",
    "chars": 7532,
    "preview": "package com.example.c001apk.compose.ui.chat\n\nimport android.net.Uri\nimport androidx.compose.runtime.getValue\nimport andr"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/collection/CollectionScreen.kt",
    "chars": 11138,
    "preview": "package com.example.c001apk.compose.ui.collection\n\nimport androidx.compose.animation.AnimatedContent\nimport androidx.com"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/collection/CollectionViewModel.kt",
    "chars": 2912,
    "preview": "package com.example.c001apk.compose.ui.collection\n\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runt"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/ArticleItem.kt",
    "chars": 3385,
    "preview": "package com.example.c001apk.compose.ui.component\n\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport androidx"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/Button.kt",
    "chars": 660,
    "preview": "package com.example.c001apk.compose.ui.component\n\nimport androidx.compose.material.icons.Icons\nimport androidx.compose.m"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/ChatEditText.kt",
    "chars": 4129,
    "preview": "package com.example.c001apk.compose.ui.component\n\nimport android.annotation.SuppressLint\nimport android.content.Context\n"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/CoilLoader.kt",
    "chars": 2478,
    "preview": "package com.example.c001apk.compose.ui.component\n\nimport android.os.Build\nimport androidx.compose.runtime.Composable\nimp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/CommonScreen.kt",
    "chars": 4918,
    "preview": "package com.example.c001apk.compose.ui.component\n\nimport androidx.compose.foundation.layout.Arrangement\nimport androidx."
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/FooterCard.kt",
    "chars": 721,
    "preview": "package com.example.c001apk.compose.ui.component\n\nimport androidx.compose.foundation.lazy.LazyListScope\nimport androidx."
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/IconText.kt",
    "chars": 2127,
    "preview": "package com.example.c001apk.compose.ui.component\n\nimport androidx.compose.foundation.text.InlineTextContent\nimport andro"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/ImageView.kt",
    "chars": 3143,
    "preview": "package com.example.c001apk.compose.ui.component\n\nimport android.graphics.Color\nimport androidx.compose.runtime.Composab"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/ItemCard.kt",
    "chars": 9808,
    "preview": "package com.example.c001apk.compose.ui.component\n\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose."
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/LinkText.kt",
    "chars": 3311,
    "preview": "package com.example.c001apk.compose.ui.component\n\nimport android.graphics.Typeface\nimport android.text.TextUtils\nimport "
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/NineImageView.kt",
    "chars": 2215,
    "preview": "package com.example.c001apk.compose.ui.component\n\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compos"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/Transitions.kt",
    "chars": 3402,
    "preview": "package com.example.c001apk.compose.ui.component\n\nimport androidx.compose.animation.core.Easing\nimport androidx.compose."
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/WebView.kt",
    "chars": 11064,
    "preview": "package com.example.c001apk.compose.ui.component\n\nimport android.annotation.SuppressLint\nimport android.app.DownloadMana"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/AppCard.kt",
    "chars": 8632,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.ExperimentalFoundationApi\nimp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/AppInfoCard.kt",
    "chars": 4929,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport an"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/AppUpdateCard.kt",
    "chars": 6438,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.animation.animateContentSize\nimport andr"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/CardIndicator.kt",
    "chars": 2901,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.animation.animateColorAsState\nimport and"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/CarouselCard.kt",
    "chars": 3605,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.background\nimport androidx.co"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/ChatLeftCard.kt",
    "chars": 4256,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.background\nimport androidx.co"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/ChatRightCard.kt",
    "chars": 4441,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.background\nimport androidx.co"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/ChatTimeCard.kt",
    "chars": 814,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport an"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/CollectionCard.kt",
    "chars": 4076,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.background\nimport androidx.co"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/FeedArticleCard.kt",
    "chars": 3253,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.background\nimport androidx.co"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/FeedCard.kt",
    "chars": 26395,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.ExperimentalFoundationApi\nimp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/FeedReplyCard.kt",
    "chars": 26728,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.ExperimentalFoundationApi\nimp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/FeedReplySortCard.kt",
    "chars": 3526,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.background\nimport androidx.co"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/HistoryCard.kt",
    "chars": 8312,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.ExperimentalFoundationApi\nimp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/IconLinkGridCard.kt",
    "chars": 3440,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.background\nimport androidx.co"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/IconMiniGridCard.kt",
    "chars": 2162,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.background\nimport androidx.co"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/IconMiniScrollCard.kt",
    "chars": 4132,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.background\nimport androidx.co"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/IconScrollCard.kt",
    "chars": 3674,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.background\nimport androidx.co"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/ImageSquareScrollCard.kt",
    "chars": 2820,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.clickable\nimport androidx.com"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/ImageTextScrollCard.kt",
    "chars": 3661,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.background\nimport androidx.co"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/LoadingCard.kt",
    "chars": 2678,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.clickable\nimport androidx.com"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/MessageCard.kt",
    "chars": 4861,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.ExperimentalFoundationApi\nimp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/MessageFFFCard.kt",
    "chars": 5217,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.Image\nimport androidx.compose"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/MessageHeaderCard.kt",
    "chars": 6032,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.animation.core.animateFloatAsState\nimpor"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/MessageListCard.kt",
    "chars": 4684,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.Image\nimport androidx.compose"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/MessageWidgetCard.kt",
    "chars": 3192,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.background\nimport androidx.co"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/NotificationCard.kt",
    "chars": 6651,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.ExperimentalFoundationApi\nimp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/SearchHistoryCard.kt",
    "chars": 1230,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.ExperimentalFoundationApi\nimp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/TextCard.kt",
    "chars": 1145,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.background\nimport androidx.co"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/TitleCard.kt",
    "chars": 1825,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.layout.Row\nimport androidx.co"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/cards/UserInfoCard.kt",
    "chars": 10873,
    "preview": "package com.example.c001apk.compose.ui.component.cards\n\nimport androidx.compose.foundation.BorderStroke\nimport androidx."
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/icons/Swatch.kt",
    "chars": 2986,
    "preview": "/*\n * ImageToolbox is an image editor for android\n * Copyright (c) 2024 T8RIN (Malik Mukhametzyanov)\n *\n * Licensed unde"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/settings/BasicListItem.kt",
    "chars": 2134,
    "preview": "package com.example.c001apk.compose.ui.component.settings\n\nimport androidx.compose.foundation.Image\nimport androidx.comp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/settings/DropdownListItem.kt",
    "chars": 2230,
    "preview": "package com.example.c001apk.compose.ui.component.settings\n\nimport androidx.compose.foundation.background\nimport androidx"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/settings/StateBasicListItem.kt",
    "chars": 2694,
    "preview": "package com.example.c001apk.compose.ui.component.settings\n\nimport androidx.compose.foundation.Image\nimport androidx.comp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/settings/StateDropdownListItem.kt",
    "chars": 2237,
    "preview": "package com.example.c001apk.compose.ui.component.settings\n\nimport androidx.compose.foundation.background\nimport androidx"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/component/settings/SwitchListItem.kt",
    "chars": 790,
    "preview": "package com.example.c001apk.compose.ui.component.settings\n\nimport androidx.compose.material3.Switch\nimport androidx.comp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/coolpic/CoolPicContentScreen.kt",
    "chars": 1512,
    "preview": "package com.example.c001apk.compose.ui.coolpic\n\nimport androidx.compose.foundation.layout.PaddingValues\nimport androidx."
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/coolpic/CoolPicContentViewModel.kt",
    "chars": 1348,
    "preview": "package com.example.c001apk.compose.ui.coolpic\n\nimport com.example.c001apk.compose.logic.model.HomeFeedResponse\nimport c"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/coolpic/CoolPicScreen.kt",
    "chars": 4928,
    "preview": "package com.example.c001apk.compose.ui.coolpic\n\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/dyh/DyhContentScreen.kt",
    "chars": 1487,
    "preview": "package com.example.c001apk.compose.ui.dyh\n\nimport androidx.compose.foundation.layout.PaddingValues\nimport androidx.comp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/dyh/DyhContentViewModel.kt",
    "chars": 1319,
    "preview": "package com.example.c001apk.compose.ui.dyh\n\nimport com.example.c001apk.compose.logic.model.HomeFeedResponse\nimport com.e"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/dyh/DyhScreen.kt",
    "chars": 4907,
    "preview": "package com.example.c001apk.compose.ui.dyh\n\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.fou"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/feed/FeedScreen.kt",
    "chars": 30144,
    "preview": "package com.example.c001apk.compose.ui.feed\n\nimport android.app.Activity.RESULT_OK\nimport android.content.Intent\nimport "
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/feed/FeedViewModel.kt",
    "chars": 29111,
    "preview": "package com.example.c001apk.compose.ui.feed\n\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mu"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/feed/reply/ReplyActivity.kt",
    "chars": 31481,
    "preview": "package com.example.c001apk.compose.ui.feed.reply\n\nimport android.annotation.SuppressLint\nimport android.content.Activit"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/feed/reply/ReplyViewModel.kt",
    "chars": 7467,
    "preview": "package com.example.c001apk.compose.ui.feed.reply\n\nimport android.graphics.Bitmap\nimport android.graphics.BitmapFactory\n"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/feed/reply/emoji/EmojiChildPagerAdapter.kt",
    "chars": 1382,
    "preview": "package com.example.c001apk.compose.ui.feed.reply.emoji\n\nimport android.view.Gravity\nimport android.view.ViewGroup\nimpor"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/feed/reply/emoji/EmojiGridAdapter.kt",
    "chars": 2485,
    "preview": "package com.example.c001apk.compose.ui.feed.reply.emoji\n\nimport android.annotation.SuppressLint\nimport android.os.Build."
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/feed/reply/emoji/EmojiPagerAdapter.kt",
    "chars": 1438,
    "preview": "package com.example.c001apk.compose.ui.feed.reply.emoji\n\nimport android.view.LayoutInflater\nimport android.view.View\nimp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/ffflist/FFFContentScreen.kt",
    "chars": 6227,
    "preview": "package com.example.c001apk.compose.ui.ffflist\n\nimport androidx.compose.foundation.clickable\nimport androidx.compose.fou"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/ffflist/FFFContentViewModel.kt",
    "chars": 4460,
    "preview": "package com.example.c001apk.compose.ui.ffflist\n\nimport androidx.lifecycle.viewModelScope\nimport com.example.c001apk.comp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/ffflist/FFFListScreen.kt",
    "chars": 10857,
    "preview": "package com.example.c001apk.compose.ui.ffflist\n\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/history/HistoryScreen.kt",
    "chars": 6280,
    "preview": "package com.example.c001apk.compose.ui.history\n\nimport androidx.compose.animation.AnimatedVisibility\nimport androidx.com"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/history/HistoryViewModel.kt",
    "chars": 2124,
    "preview": "package com.example.c001apk.compose.ui.history\n\nimport androidx.lifecycle.ViewModel\nimport androidx.lifecycle.viewModelS"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/home/HomeScreen.kt",
    "chars": 8050,
    "preview": "package com.example.c001apk.compose.ui.home\n\nimport android.content.Intent\nimport androidx.compose.animation.AnimatedVis"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/home/app/AppListScreen.kt",
    "chars": 5527,
    "preview": "package com.example.c001apk.compose.ui.home.app\n\nimport androidx.compose.animation.AnimatedVisibility\nimport androidx.co"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/home/app/AppListViewModel.kt",
    "chars": 2694,
    "preview": "package com.example.c001apk.compose.ui.home.app\n\nimport android.content.pm.ApplicationInfo\nimport android.content.pm.Pac"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/home/feed/HomeFeedScreen.kt",
    "chars": 3522,
    "preview": "package com.example.c001apk.compose.ui.home.feed\n\nimport androidx.compose.runtime.Composable\nimport androidx.compose.run"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/home/feed/HomeFeedViewModel.kt",
    "chars": 2422,
    "preview": "package com.example.c001apk.compose.ui.home.feed\n\nimport androidx.lifecycle.viewModelScope\nimport com.example.c001apk.co"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/home/topic/HomeTopicScreen.kt",
    "chars": 8637,
    "preview": "package com.example.c001apk.compose.ui.home.topic\n\nimport androidx.compose.foundation.background\nimport androidx.compose"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/home/topic/HomeTopicViewModel.kt",
    "chars": 954,
    "preview": "package com.example.c001apk.compose.ui.home.topic\n\nimport com.example.c001apk.compose.logic.repository.BlackListRepo\nimp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/login/LoginScreen.kt",
    "chars": 9883,
    "preview": "package com.example.c001apk.compose.ui.login\n\nimport androidx.compose.animation.AnimatedVisibility\nimport androidx.compo"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/login/LoginViewModel.kt",
    "chars": 6190,
    "preview": "package com.example.c001apk.compose.ui.login\n\nimport android.graphics.Bitmap\nimport android.graphics.BitmapFactory\nimpor"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/main/MainActivity.kt",
    "chars": 6366,
    "preview": "package com.example.c001apk.compose.ui.main\n\nimport android.content.Intent\nimport android.os.Bundle\nimport androidx.acti"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/main/MainNavigation.kt",
    "chars": 35131,
    "preview": "package com.example.c001apk.compose.ui.main\n\nimport android.content.Context\nimport android.net.Uri\nimport android.os.Bui"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/main/MainScreen.kt",
    "chars": 7296,
    "preview": "package com.example.c001apk.compose.ui.main\n\nimport androidx.activity.compose.BackHandler\nimport androidx.compose.animat"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/main/MainViewModel.kt",
    "chars": 3230,
    "preview": "package com.example.c001apk.compose.ui.main\n\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mu"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/main/Router.kt",
    "chars": 2619,
    "preview": "package com.example.c001apk.compose.ui.main\n\nimport androidx.annotation.StringRes\nimport androidx.compose.material.icons"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/message/MessageScreen.kt",
    "chars": 9684,
    "preview": "package com.example.c001apk.compose.ui.message\n\nimport androidx.compose.foundation.layout.Arrangement\nimport androidx.co"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/message/MessageViewModel.kt",
    "chars": 6061,
    "preview": "package com.example.c001apk.compose.ui.message\n\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/notification/NoticeScreen.kt",
    "chars": 7120,
    "preview": "package com.example.c001apk.compose.ui.notification\n\nimport androidx.compose.foundation.clickable\nimport androidx.compos"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/notification/NoticeViewModel.kt",
    "chars": 4176,
    "preview": "package com.example.c001apk.compose.ui.notification\n\nimport androidx.lifecycle.viewModelScope\nimport com.example.c001apk"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/others/CopyTextScreen.kt",
    "chars": 1829,
    "preview": "package com.example.c001apk.compose.ui.others\n\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.fou"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/search/SearchContentScreen.kt",
    "chars": 3557,
    "preview": "package com.example.c001apk.compose.ui.search\n\nimport androidx.compose.foundation.layout.PaddingValues\nimport androidx.c"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/search/SearchContentViewModel.kt",
    "chars": 1810,
    "preview": "package com.example.c001apk.compose.ui.search\n\nimport com.example.c001apk.compose.logic.model.HomeFeedResponse\nimport co"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/search/SearchResultScreen.kt",
    "chars": 14011,
    "preview": "package com.example.c001apk.compose.ui.search\n\nimport androidx.compose.animation.fadeIn\nimport androidx.compose.animatio"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/search/SearchScreen.kt",
    "chars": 10307,
    "preview": "package com.example.c001apk.compose.ui.search\n\nimport androidx.compose.animation.AnimatedVisibility\nimport androidx.comp"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/search/SearchViewModel.kt",
    "chars": 1299,
    "preview": "package com.example.c001apk.compose.ui.search\n\nimport androidx.lifecycle.ViewModel\nimport androidx.lifecycle.viewModelSc"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/settings/AboutScreen.kt",
    "chars": 4062,
    "preview": "package com.example.c001apk.compose.ui.settings\n\nimport androidx.compose.foundation.Image\nimport androidx.compose.founda"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/settings/LicenseScreen.kt",
    "chars": 5234,
    "preview": "package com.example.c001apk.compose.ui.settings\n\nimport androidx.compose.foundation.layout.PaddingValues\nimport androidx"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/settings/ParamsScreen.kt",
    "chars": 7557,
    "preview": "package com.example.c001apk.compose.ui.settings\n\nimport androidx.compose.foundation.layout.Column\nimport androidx.compos"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/settings/SettingsScreen.kt",
    "chars": 26731,
    "preview": "package com.example.c001apk.compose.ui.settings\n\nimport androidx.compose.foundation.Image\nimport androidx.compose.founda"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/settings/SettingsViewModel.kt",
    "chars": 5119,
    "preview": "package com.example.c001apk.compose.ui.settings\n\nimport androidx.lifecycle.viewModelScope\nimport com.example.c001apk.com"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/theme/Color.kt",
    "chars": 454,
    "preview": "package com.example.c001apk.compose.ui.theme\n\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.ru"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/theme/Theme.kt",
    "chars": 6378,
    "preview": "package com.example.c001apk.compose.ui.theme\n\nimport android.app.Activity\nimport android.os.Build.VERSION.SDK_INT\nimport"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/theme/Type.kt",
    "chars": 996,
    "preview": "package com.example.c001apk.compose.ui.theme\n\nimport androidx.compose.material3.Typography\nimport androidx.compose.ui.te"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/topic/TopicContentScreen.kt",
    "chars": 2518,
    "preview": "package com.example.c001apk.compose.ui.topic\n\nimport androidx.compose.foundation.layout.PaddingValues\nimport androidx.co"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/topic/TopicContentViewModel.kt",
    "chars": 1466,
    "preview": "package com.example.c001apk.compose.ui.topic\n\nimport com.example.c001apk.compose.constant.Constants.EMPTY_STRING\nimport "
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/topic/TopicScreen.kt",
    "chars": 18676,
    "preview": "package com.example.c001apk.compose.ui.topic\n\nimport android.content.Intent\nimport androidx.compose.animation.AnimatedVi"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/topic/TopicViewModel.kt",
    "chars": 5249,
    "preview": "package com.example.c001apk.compose.ui.topic\n\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.m"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/user/UserScreen.kt",
    "chars": 14306,
    "preview": "package com.example.c001apk.compose.ui.user\n\nimport androidx.compose.foundation.layout.Arrangement\nimport androidx.compo"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/user/UserViewModel.kt",
    "chars": 4336,
    "preview": "package com.example.c001apk.compose.ui.user\n\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mu"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/webview/WebViewScreen.kt",
    "chars": 8807,
    "preview": "package com.example.c001apk.compose.ui.webview\n\nimport androidx.activity.compose.BackHandler\nimport androidx.compose.ani"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/ui/webview/WebViewViewModel.kt",
    "chars": 819,
    "preview": "package com.example.c001apk.compose.ui.webview\n\nimport androidx.lifecycle.ViewModel\nimport androidx.lifecycle.viewModelS"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/util/AddCookiesInterceptor.kt",
    "chars": 2154,
    "preview": "package com.example.c001apk.compose.util\n\nimport com.example.c001apk.compose.constant.Constants.APP_ID\nimport com.exampl"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/util/Base64Utils.kt",
    "chars": 5652,
    "preview": "package com.example.c001apk.compose.util\n\nimport java.io.UnsupportedEncodingException\nimport java.nio.charset.StandardCh"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/util/CacheDataManager.kt",
    "chars": 2783,
    "preview": "package com.example.c001apk.compose.util\n\nimport android.content.Context\nimport android.os.Environment\nimport coil.Coil\n"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/util/CommentHelper.kt",
    "chars": 6898,
    "preview": "package com.example.c001apk.compose.util\n\nimport android.content.Context\nimport android.text.Editable\nimport android.tex"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/util/CookieUtil.kt",
    "chars": 1344,
    "preview": "package com.example.c001apk.compose.util\n\nimport com.example.c001apk.compose.constant.Constants.API_VERSION\nimport com.e"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/util/DateUtils.kt",
    "chars": 6851,
    "preview": "package com.example.c001apk.compose.util\n\nimport android.annotation.SuppressLint\nimport java.text.SimpleDateFormat\nimpor"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/util/EmojiUtils.kt",
    "chars": 9994,
    "preview": "package com.example.c001apk.compose.util\n\nimport com.example.c001apk.compose.R\n\n/**\n * Created by bggRGjQaUbCoE on 2024/"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/util/Extensions.kt",
    "chars": 7260,
    "preview": "package com.example.c001apk.compose.util\n\nimport android.content.ClipData\nimport android.content.ClipboardManager\nimport"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/util/ImageDownloadUtil.kt",
    "chars": 4833,
    "preview": "package com.example.c001apk.compose.util\n\nimport android.content.ContentValues\nimport android.content.Context\nimport and"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/util/ImageShowUtil.kt",
    "chars": 11508,
    "preview": "package com.example.c001apk.compose.util\n\nimport android.content.ActivityNotFoundException\nimport android.content.Contex"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/util/LoginCookiesInterceptor.kt",
    "chars": 6821,
    "preview": "package com.example.c001apk.compose.util\n\nimport com.example.c001apk.compose.constant.Constants.APP_ID\nimport com.exampl"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/util/NetWorkUtil.kt",
    "chars": 895,
    "preview": "package com.example.c001apk.compose.util\n\nimport android.content.Context\nimport android.net.ConnectivityManager\nimport a"
  },
  {
    "path": "app/src/main/java/com/example/c001apk/compose/util/OSSUtil.kt",
    "chars": 2910,
    "preview": "package com.example.c001apk.compose.util\n\nimport android.content.ContentResolver\nimport android.graphics.BitmapFactory\ni"
  }
]

// ... and 75 more files (download for full content)

About this extraction

This page contains the full source code of the bggRGjQaUbCoE/c001apk-compose GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 275 files (1.1 MB), approximately 258.2k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!