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. 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. Copyright (C) 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 . 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 . ================================================ 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* { ; } -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 ; } # 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 ; } # Preserve annotated Javascript interface methods. -keepclassmembers class * { @android.webkit.JavascriptInterface ; } # 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 ; } -keepclasseswithmembers class * { @androidx.annotation.Keep ; } -keepclasseswithmembers class * { @androidx.annotation.Keep (...); } -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 { (...); } # ViewModel's empty constructor is considered to be unused by proguard -keepclassmembers class * extends androidx.lifecycle.ViewModel { (...); } # 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.** { ; } # 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 ; } # 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.* ; } -keepclasseswithmembers interface * { @retrofit2.* ; } -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 ================================================ ================================================ 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 = 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 @Query("SELECT * FROM FeedEntity ORDER BY time DESC") fun loadAllListLive(): LiveData> @Query("SELECT * FROM FeedEntity ORDER BY time DESC") fun loadAllListFlow(): Flow> @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) @Query("SELECT * FROM HomeMenu ORDER BY position ASC") suspend fun loadAllList(): List @Query("SELECT * FROM HomeMenu ORDER BY position ASC") fun loadAllListLive(): LiveData> @Query("SELECT * FROM HomeMenu ORDER BY position ASC") fun loadAllListFlow(): Flow> @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) } ================================================ 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) @Query("SELECT * FROM RecentAtUser ORDER BY id DESC") suspend fun loadAllList(): List @Query("SELECT * FROM RecentAtUser ORDER BY id DESC") fun loadAllListLive(): LiveData> @Query("SELECT * FROM RecentAtUser ORDER BY id DESC") fun loadAllListFlow(): Flow> @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) @Query("SELECT * FROM StringEntity ORDER BY id DESC") suspend fun loadAllList(): List @Query("SELECT * FROM StringEntity ORDER BY id DESC") fun loadAllListLive(): LiveData> @Query("SELECT * FROM StringEntity ORDER BY id DESC") fun loadAllListFlow(): Flow> @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 ) { 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 { 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?, ) } ================================================ 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 create(gson: Gson, type: TypeToken): TypeAdapter { return FeedAdapter(gson) as TypeAdapter } } class FeedAdapter(private val gson: Gson) : TypeAdapter() { @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?, ) { @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?, @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?, val targetRow: TargetRow?, @SerializedName("change_count") val changeCount: Int?, val isModified: Int?, @SerializedName("ip_location") val ipLocation: String?, val isFeedAuthor: Int?, var topReplyRows: List?, val extraDataArr: ExtraDataArr?, val intro: String?, @SerializedName("tag_pics") val tagPics: List?, val tabList: List?, val displayUsername: String?, val cover: String?, val selectedTab: String?, val homeTabCardRows: List?, @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?, 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?, var replyRows: List?, 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?, ) : 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