├── .gitignore
├── .idea
├── compiler.xml
├── gradle.xml
├── jarRepositories.xml
├── misc.xml
└── vcs.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── personal.text
├── proguard-rules.pro
├── release
│ └── output-metadata.json
├── schemas
│ └── com.yollpoll.nmb.db.MainDB
│ │ └── 1.json
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── yollpoll
│ │ └── nmb
│ │ └── ExampleInstrumentedTest.kt
│ ├── cpp
│ ├── includes
│ │ └── native-lib.h
│ └── native-lib.cpp
│ ├── main
│ ├── AndroidManifest.xml
│ ├── cpp
│ │ ├── CMakeLists.txt
│ │ └── nmb.cpp
│ ├── java
│ │ └── com
│ │ │ └── yollpoll
│ │ │ └── nmb
│ │ │ ├── AboutProject.kt
│ │ │ ├── App.kt
│ │ │ ├── MyCrashHandler.kt
│ │ │ ├── adapter
│ │ │ ├── ExampleLoadStateAdapter.kt
│ │ │ ├── ImagePagerAdapter.kt
│ │ │ └── ThreadAdapter.kt
│ │ │ ├── db
│ │ │ ├── ArticleDao.kt
│ │ │ ├── BaseDao.kt
│ │ │ ├── CookieDao.kt
│ │ │ ├── DraftDao.kt
│ │ │ ├── ForumDao.kt
│ │ │ ├── HistoryDao.kt
│ │ │ ├── MainDB.kt
│ │ │ └── MySpeechDao.kt
│ │ │ ├── di
│ │ │ ├── AppWidgetDI.kt
│ │ │ ├── ArgumentsDI.kt
│ │ │ ├── ArticleDetailViewModelDI.kt
│ │ │ ├── CommonDi.kt
│ │ │ ├── DBModuleDI.kt
│ │ │ ├── DiAnnotation.kt
│ │ │ ├── HomeViewModelDI.kt
│ │ │ ├── LauncherViewModelDI.kt
│ │ │ ├── NetModuleDI.kt
│ │ │ └── RepositoryDI.kt
│ │ │ ├── model
│ │ │ ├── bean
│ │ │ │ ├── Announcement.kt
│ │ │ │ ├── Article.kt
│ │ │ │ ├── CookieBean.kt
│ │ │ │ ├── DraftBean.kt
│ │ │ │ ├── Fourm.kt
│ │ │ │ ├── HistoryBean.kt
│ │ │ │ ├── MySpeechBean.kt
│ │ │ │ └── SettingBean.kt
│ │ │ └── repository
│ │ │ │ ├── ArticleDetailRepository.kt
│ │ │ │ ├── CookieRepository.kt
│ │ │ │ ├── DraftRepository.kt
│ │ │ │ ├── ForumRepository.kt
│ │ │ │ ├── HomeRepository.kt
│ │ │ │ ├── IRepository.kt
│ │ │ │ ├── LauncherRepository.kt
│ │ │ │ └── UserRepository.kt
│ │ │ ├── net
│ │ │ ├── Cookie.kt
│ │ │ ├── CoverImgInterceptor.kt
│ │ │ ├── HttpService.kt
│ │ │ ├── HttpServiceFactory.kt
│ │ │ ├── LoggerInterceptor.kt
│ │ │ ├── NMBInterceptor.kt
│ │ │ ├── Url.kt
│ │ │ └── Utils.kt
│ │ │ ├── router
│ │ │ ├── Dispatch.kt
│ │ │ └── Route.kt
│ │ │ ├── schedule
│ │ │ └── UpdateAppWidgetWork.kt
│ │ │ ├── service
│ │ │ ├── ThreadReplyService.kt
│ │ │ └── UpdateThreadWidgetService.kt
│ │ │ └── view
│ │ │ ├── activity
│ │ │ ├── AuthorActivity.kt
│ │ │ ├── CollectionActivity.kt
│ │ │ ├── CookieActivity.kt
│ │ │ ├── DraftActivity.kt
│ │ │ ├── DrawingActivity.kt
│ │ │ ├── DrawingActivity2.java
│ │ │ ├── ForumSettingActivity.kt
│ │ │ ├── HistoryActivity.kt
│ │ │ ├── HomeActivity.kt
│ │ │ ├── ImageActivity.kt
│ │ │ ├── LauncherActivity.kt
│ │ │ ├── MySpeechActivity.kt
│ │ │ ├── NewThreadActivity.kt
│ │ │ ├── QRActivity.kt
│ │ │ ├── SettingActivity.kt
│ │ │ ├── ShieldActivity.kt
│ │ │ ├── ThreadDetailActivity.kt
│ │ │ ├── ThreadImageActivity.kt
│ │ │ └── WebActivity.kt
│ │ │ └── widgets
│ │ │ ├── BindAdapter.kt
│ │ │ ├── ChangeBurshWidthView.java
│ │ │ ├── ChangeLineViewGroup.java
│ │ │ ├── DrawView.java
│ │ │ ├── ImportCollectionDialog.kt
│ │ │ ├── InputDialog.kt
│ │ │ ├── LinkArticleDialog.kt
│ │ │ ├── MyFAB.kt
│ │ │ ├── MyFloatingMenu.kt
│ │ │ ├── MyImageView.kt
│ │ │ ├── SelectColorDialog.kt
│ │ │ ├── SelectPageDialog.kt
│ │ │ ├── ThreadMenuDialog.kt
│ │ │ ├── ThreadWidget.kt
│ │ │ ├── Utils.kt
│ │ │ ├── VSensorLayout.kt
│ │ │ ├── emoji
│ │ │ ├── ChooseEmojiDialogFragment.kt
│ │ │ ├── EmojiUtils.kt
│ │ │ ├── PicEmojiAdapter.kt
│ │ │ └── WordEmojiAdapter.kt
│ │ │ └── tag
│ │ │ └── ChooseTagActivity.kt
│ └── res
│ │ ├── anim
│ │ ├── new_thread_anim.xml
│ │ ├── new_thread_anim_close.xml
│ │ └── new_thread_layout_anim.xml
│ │ ├── drawable-night
│ │ └── ic_checked.xml
│ │ ├── drawable-v24
│ │ ├── ic_launcher_foreground.xml
│ │ ├── ic_logo.png
│ │ └── shape_new_thread_tag.xml
│ │ ├── drawable
│ │ ├── ic_add_cookie.xml
│ │ ├── ic_checked.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ripple_forum.xml
│ │ ├── ripple_forum_hide.xml
│ │ ├── ripple_item.xml
│ │ ├── ripple_widget.xml
│ │ ├── shape_cookie_color.xml
│ │ ├── shape_drawer.xml
│ │ ├── shape_line.xml
│ │ ├── shape_right_drawer.xml
│ │ └── shape_tag.xml
│ │ ├── layout
│ │ ├── activity_author.xml
│ │ ├── activity_choose_tag.xml
│ │ ├── activity_collection.xml
│ │ ├── activity_cookie.xml
│ │ ├── activity_draft.xml
│ │ ├── activity_drawing.xml
│ │ ├── activity_forum_setting.xml
│ │ ├── activity_history.xml
│ │ ├── activity_home.xml
│ │ ├── activity_image.xml
│ │ ├── activity_main.xml
│ │ ├── activity_my_speech.xml
│ │ ├── activity_newthread.xml
│ │ ├── activity_qr.xml
│ │ ├── activity_setting.xml
│ │ ├── activity_shield.xml
│ │ ├── activity_thread_detail.xml
│ │ ├── activity_thread_image.xml
│ │ ├── activity_web.xml
│ │ ├── alert_choose_photo.xml
│ │ ├── dialog_brush_width.xml
│ │ ├── dialog_choose_color.xml
│ │ ├── dialog_choose_emoji.xml
│ │ ├── dialog_import_collection.xml
│ │ ├── dialog_input.xml
│ │ ├── dialog_select_color.xml
│ │ ├── dialog_select_page.xml
│ │ ├── dialog_thread_menu.xml
│ │ ├── fragment_image.xml
│ │ ├── include_drawer.xml
│ │ ├── include_title.xml
│ │ ├── item_cookie.xml
│ │ ├── item_draft.xml
│ │ ├── item_for_custom_spinner.xml
│ │ ├── item_forum.xml
│ │ ├── item_history.xml
│ │ ├── item_pic_emoji.xml
│ │ ├── item_setting_forum.xml
│ │ ├── item_speech.xml
│ │ ├── item_tag.xml
│ │ ├── item_thread.xml
│ │ ├── item_word_emoji.xml
│ │ ├── load_state_item.xml
│ │ └── widget_thread.xml
│ │ ├── menu
│ │ ├── menu_article_detail.xml
│ │ ├── menu_collection.xml
│ │ ├── menu_cookie.xml
│ │ ├── menu_drawer.xml
│ │ ├── menu_history.xml
│ │ ├── menu_home.xml
│ │ ├── menu_img.xml
│ │ ├── menu_new_thread.xml
│ │ └── menu_web.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ ├── ic_launcher_round.xml
│ │ ├── icon_drawer.png
│ │ ├── icon_emoji.png
│ │ ├── icon_pic.png
│ │ └── icon_send.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_send.png
│ │ ├── icon_show.png
│ │ ├── lwn_1.png
│ │ ├── lwn_10.png
│ │ ├── lwn_100.png
│ │ ├── lwn_101.png
│ │ ├── lwn_102.png
│ │ ├── lwn_103.png
│ │ ├── lwn_104.png
│ │ ├── lwn_105.png
│ │ ├── lwn_106.png
│ │ ├── lwn_11.png
│ │ ├── lwn_12.png
│ │ ├── lwn_13.png
│ │ ├── lwn_14.png
│ │ ├── lwn_15.png
│ │ ├── lwn_16.png
│ │ ├── lwn_17.png
│ │ ├── lwn_18.png
│ │ ├── lwn_19.png
│ │ ├── lwn_2.png
│ │ ├── lwn_20.png
│ │ ├── lwn_21.png
│ │ ├── lwn_22.png
│ │ ├── lwn_23.png
│ │ ├── lwn_24.png
│ │ ├── lwn_25.png
│ │ ├── lwn_26.png
│ │ ├── lwn_27.png
│ │ ├── lwn_28.png
│ │ ├── lwn_29.png
│ │ ├── lwn_3.png
│ │ ├── lwn_30.png
│ │ ├── lwn_31.png
│ │ ├── lwn_32.png
│ │ ├── lwn_33.png
│ │ ├── lwn_34.png
│ │ ├── lwn_35.png
│ │ ├── lwn_36.png
│ │ ├── lwn_37.png
│ │ ├── lwn_38.png
│ │ ├── lwn_39.png
│ │ ├── lwn_4.png
│ │ ├── lwn_40.png
│ │ ├── lwn_41.png
│ │ ├── lwn_42.png
│ │ ├── lwn_43.png
│ │ ├── lwn_44.png
│ │ ├── lwn_45.png
│ │ ├── lwn_46.png
│ │ ├── lwn_47.png
│ │ ├── lwn_48.png
│ │ ├── lwn_49.png
│ │ ├── lwn_5.png
│ │ ├── lwn_50.png
│ │ ├── lwn_51.png
│ │ ├── lwn_52.png
│ │ ├── lwn_53.png
│ │ ├── lwn_54.png
│ │ ├── lwn_55.png
│ │ ├── lwn_56.png
│ │ ├── lwn_57.png
│ │ ├── lwn_58.png
│ │ ├── lwn_59.png
│ │ ├── lwn_6.png
│ │ ├── lwn_60.png
│ │ ├── lwn_61.png
│ │ ├── lwn_62.png
│ │ ├── lwn_63.png
│ │ ├── lwn_64.png
│ │ ├── lwn_65.png
│ │ ├── lwn_66.png
│ │ ├── lwn_67.png
│ │ ├── lwn_68.png
│ │ ├── lwn_69.png
│ │ ├── lwn_7.png
│ │ ├── lwn_70.png
│ │ ├── lwn_71.png
│ │ ├── lwn_72.png
│ │ ├── lwn_73.png
│ │ ├── lwn_74.png
│ │ ├── lwn_75.png
│ │ ├── lwn_76.png
│ │ ├── lwn_77.png
│ │ ├── lwn_78.png
│ │ ├── lwn_79.png
│ │ ├── lwn_8.png
│ │ ├── lwn_80.png
│ │ ├── lwn_81.png
│ │ ├── lwn_82.png
│ │ ├── lwn_83.png
│ │ ├── lwn_84.png
│ │ ├── lwn_85.png
│ │ ├── lwn_86.png
│ │ ├── lwn_87.png
│ │ ├── lwn_88.png
│ │ ├── lwn_89.png
│ │ ├── lwn_9.png
│ │ ├── lwn_90.png
│ │ ├── lwn_91.png
│ │ ├── lwn_92.png
│ │ ├── lwn_93.png
│ │ ├── lwn_94.png
│ │ ├── lwn_95.png
│ │ ├── lwn_96.png
│ │ ├── lwn_97.png
│ │ ├── lwn_98.png
│ │ └── lwn_99.png
│ │ ├── mipmap-night-xxxhdpi
│ │ ├── ic_action.png
│ │ └── ic_github.png
│ │ ├── mipmap-xhdpi
│ │ ├── icon_cleaner.png
│ │ ├── icon_cleaner_fill.png
│ │ ├── icon_clear.png
│ │ ├── icon_draw_color.png
│ │ ├── icon_draw_menu.png
│ │ └── icon_draw_width.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── app_widget_pic.png
│ │ ├── bg_cover.png
│ │ ├── ic_ac.png
│ │ ├── ic_action.png
│ │ ├── ic_cookie.png
│ │ ├── ic_donate.png
│ │ ├── ic_download.png
│ │ ├── ic_drawer.png
│ │ ├── ic_emoji.png
│ │ ├── ic_full_screen.png
│ │ ├── ic_full_screen_selected.png
│ │ ├── ic_github.png
│ │ ├── ic_logo.png
│ │ └── ic_pic.png
│ │ ├── values-night
│ │ └── themes.xml
│ │ ├── values
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── dimen.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ │ └── xml
│ │ ├── app_widgets_thread.xml
│ │ ├── provider_paths.xml
│ │ └── shortcuts.xml
│ └── test
│ └── java
│ └── com
│ └── yollpoll
│ └── nmb
│ └── ExampleUnitTest.kt
├── base
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── yollpoll
│ │ └── base
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── yollpoll
│ │ │ ├── base
│ │ │ ├── AnnouncementDialog.kt
│ │ │ ├── BaseAdapter.kt
│ │ │ ├── BaseDialogFragment.kt
│ │ │ ├── BasePagingSource.kt
│ │ │ ├── CommonDialog.kt
│ │ │ ├── Constant.kt
│ │ │ ├── Extension.kt
│ │ │ ├── NMBActivity.kt
│ │ │ ├── NMBApplication.kt
│ │ │ ├── NMBDialog.java
│ │ │ └── NmbBaseAdapter.kt
│ │ │ ├── extensions
│ │ │ └── context.kt
│ │ │ ├── floweventbus
│ │ │ ├── BusInterceptor.kt
│ │ │ └── FlowEventBus.kt
│ │ │ ├── skin
│ │ │ ├── Skin.kt
│ │ │ ├── SkinConfig.kt
│ │ │ ├── SkinHandler.kt
│ │ │ └── SkinInflaterFactory.kt
│ │ │ └── utils
│ │ │ ├── BitmapUtils.kt
│ │ │ ├── ClickSpanMovementMethod.kt
│ │ │ ├── ImageDownloader.kt
│ │ │ ├── ImageUtils.kt
│ │ │ ├── MyClickableSpan.kt
│ │ │ ├── TransFormContent.kt
│ │ │ └── Utils.kt
│ └── res
│ │ ├── animator
│ │ └── material_item_animator.xml
│ │ ├── drawable-night
│ │ └── shape_material_item.xml
│ │ ├── drawable
│ │ ├── shape_dialog.xml
│ │ └── shape_material_item.xml
│ │ ├── layout
│ │ ├── dialog_common.xml
│ │ └── dialog_layout.xml
│ │ ├── mipmap
│ │ └── bg_cover.png
│ │ ├── values-night
│ │ └── themes.xml
│ │ └── values
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── dimen.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ └── test
│ └── java
│ └── com
│ └── yollpoll
│ └── base
│ └── ExampleUnitTest.kt
├── build-framework.gradle
├── build.gradle
├── business
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── yollpoll
│ │ └── business
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── yollpoll
│ │ │ └── business
│ │ │ └── TestActivity.kt
│ └── res
│ │ ├── layout
│ │ └── activity_home.xml
│ │ └── values
│ │ ├── colors.xml
│ │ └── dimen.xml
│ └── test
│ └── java
│ └── com
│ └── yollpoll
│ └── business
│ └── ExampleUnitTest.kt
├── config.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── ilog
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── yollpoll
│ │ └── ilog
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ └── java
│ │ └── com
│ │ └── yollpoll
│ │ └── ilog
│ │ └── Ilog.kt
│ └── test
│ └── java
│ └── com
│ └── yollpoll
│ └── ilog
│ └── ExampleUnitTest.kt
├── iqr
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── yollpoll
│ │ └── nmb
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ └── java
│ │ └── com
│ │ └── yollpoll
│ │ └── nmb
│ │ └── Iqr.kt
│ └── test
│ └── java
│ └── com
│ └── yollpoll
│ └── nmb
│ └── ExampleUnitTest.kt
├── log
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── yollpoll
│ │ └── log
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ └── java
│ │ └── com
│ │ └── yollpoll
│ │ └── log
│ │ ├── CloseUtils.java
│ │ ├── FileUtils.java
│ │ ├── FileWriter.java
│ │ ├── ILogImpl.kt
│ │ ├── LogReceiver.java
│ │ ├── LogService.java
│ │ ├── LogTools.java
│ │ ├── LogWorker.kt
│ │ └── MKFileIOUtils.java
│ └── test
│ └── java
│ └── com
│ └── yollpoll
│ └── log
│ └── ExampleUnitTest.kt
├── qrlib
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── yollpoll
│ │ └── qrlib
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── yollpoll
│ │ │ └── qrlib
│ │ │ ├── QRCodeActivity.kt
│ │ │ ├── QrCodeAnalyzer.kt
│ │ │ ├── QrUtils.kt
│ │ │ └── ScanView.kt
│ └── res
│ │ ├── drawable
│ │ ├── ic_photo.xml
│ │ ├── icon_focus.png
│ │ └── scan_light.png
│ │ └── layout
│ │ └── activity_qr_code.xml
│ └── test
│ └── java
│ └── com
│ └── yollpoll
│ └── qrlib
│ └── ExampleUnitTest.kt
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | /.idea/
11 | .DS_Store
12 | /build
13 | /captures
14 | .externalNativeBuild
15 | .cxx
16 | local.properties
17 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
25 |
26 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | X岛Android客户端
2 | 语言: kotlin
3 | 最低系统版本: android 5.0
4 | 采用最新Material You,根据系统定制app配色,快去修改系统颜色试试吧。
5 | 操作说明:首页右下角按钮分别支持左滑(弹出板块选择)、右滑(弹出设置)、上滑(回到列表顶部)、下滑(刷新)、点击(发新串)
6 | 后续计划:准备搞一个跑团功能,我观察到跑团比较容易出现各种分支和各说各的,所以准备加入树状图和强制收缩时间线的功能,目前还没有什么头绪。
7 |
8 | 技术说明:
9 | 整体项目采用MVVM+APT动态代码生成+组件化+依赖注入。
10 | 其中基础架构全部由我自己实现,参考主页中的其他项目(已发布MavenCenter,接入方式具体看wiki):
11 | 基础架构:https://github.com/yollpoll/framework/wiki/%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95
12 | 路由组建:https://github.com/yollpoll/sRouter
13 | 依赖注入采用hilt。
14 | 出于练手的目的,项目大量采用jetpack库内容,欢迎交流学习,这年头还在深入学习android的不多了好寂寞
15 |
16 | 联动:
17 | 好多年前写的A岛客户端(肥宅岛)(停止维护):
18 | https://github.com/yollpoll/MyApp
19 | 另有一个采用compose开发的客户端(鸽中):
20 | https://github.com/yollpoll/nmbAndroidCompose
21 | 另有一个electron的桌面客户端(鸽中):
22 | https://github.com/yollpoll/nmb_electron
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 | -ignorewarnings
23 | -keepattributes *Annotation*
24 | -keepattributes Exceptions
25 | -keepattributes InnerClasses
26 | -keepattributes Signature
27 | -keepattributes SourceFile,LineNumberTable
28 | -keep class com.hianalytics.android.**{*;}
29 | -keep class com.huawei.**{*;}
30 |
--------------------------------------------------------------------------------
/app/release/output-metadata.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 2,
3 | "artifactType": {
4 | "type": "APK",
5 | "kind": "Directory"
6 | },
7 | "applicationId": "com.yollpoll.nmb",
8 | "variantName": "release",
9 | "elements": [
10 | {
11 | "type": "SINGLE",
12 | "filters": [],
13 | "versionCode": 1,
14 | "versionName": "0.0.1",
15 | "outputFile": "app-release.apk"
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/app/schemas/com.yollpoll.nmb.db.MainDB/1.json:
--------------------------------------------------------------------------------
1 | {
2 | "formatVersion": 1,
3 | "database": {
4 | "version": 1,
5 | "identityHash": "e66a989af2ab557f8fd42a97ad5c6ce2",
6 | "entities": [
7 | {
8 | "tableName": "CookieBean",
9 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`cookie` TEXT NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`name`))",
10 | "fields": [
11 | {
12 | "fieldPath": "cookie",
13 | "columnName": "cookie",
14 | "affinity": "TEXT",
15 | "notNull": true
16 | },
17 | {
18 | "fieldPath": "name",
19 | "columnName": "name",
20 | "affinity": "TEXT",
21 | "notNull": true
22 | }
23 | ],
24 | "primaryKey": {
25 | "columnNames": [
26 | "name"
27 | ],
28 | "autoGenerate": false
29 | },
30 | "indices": [],
31 | "foreignKeys": []
32 | }
33 | ],
34 | "views": [],
35 | "setupQueries": [
36 | "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
37 | "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'e66a989af2ab557f8fd42a97ad5c6ce2')"
38 | ]
39 | }
40 | }
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/yollpoll/nmb/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.yollpoll.nmb", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/cpp/includes/native-lib.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 宋鹏祺 on 2023/1/5.
3 | //
4 |
5 | #ifndef NMB_NATIVE_LIB_H
6 | #define NMB_NATIVE_LIB_H
7 |
8 | #endif //NMB_NATIVE_LIB_H
9 |
--------------------------------------------------------------------------------
/app/src/cpp/native-lib.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 宋鹏祺 on 2023/1/5.
3 | //
4 |
5 | #include "native-lib.h"
6 |
--------------------------------------------------------------------------------
/app/src/main/cpp/CMakeLists.txt:
--------------------------------------------------------------------------------
1 |
2 | # For more information about using CMake with Android Studio, read the
3 | # documentation: https://d.android.com/studio/projects/add-native-code.html
4 |
5 | # Sets the minimum version of CMake required to build the native library.
6 |
7 | cmake_minimum_required(VERSION 3.18.1)
8 |
9 | # Declares and names the project.
10 |
11 | project("nmb")
12 |
13 | # Creates and names a library, sets it as either STATIC
14 | # or SHARED, and provides the relative paths to its source code.
15 | # You can define multiple libraries, and CMake builds them for you.
16 | # Gradle automatically packages shared libraries with your APK.
17 |
18 | add_library( # Sets the name of the library.
19 | nmb
20 |
21 | # Sets the library as a shared library.
22 | SHARED
23 |
24 | # Provides a relative path to your source file(s).
25 | nmb.cpp )
26 |
27 | # Searches for a specified prebuilt library and stores the path as a
28 | # variable. Because CMake includes system libraries in the search path by
29 | # default, you only need to specify the name of the public NDK library
30 | # you want to add. CMake verifies that the library exists before
31 | # completing its build.
32 |
33 | find_library( # Sets the name of the path variable.
34 | log-lib
35 |
36 | # Specifies the name of the NDK library that
37 | # you want CMake to locate.
38 | log )
39 |
40 | # Specifies libraries CMake should link to your target library. You
41 | # can link multiple libraries, such as libraries you define in this
42 | # build script, prebuilt third-party libraries, or system libraries.
43 |
44 | target_link_libraries( # Specifies the target library.
45 | nmb
46 |
47 | # Links the target library to the log library
48 | # included in the NDK.
49 | ${log-lib} )
50 |
--------------------------------------------------------------------------------
/app/src/main/cpp/nmb.cpp:
--------------------------------------------------------------------------------
1 | // Write C++ code here.
2 | //
3 | // Do not forget to dynamically load the C++ library into your application.
4 | //
5 | // For instance,
6 | //
7 | // In MainActivity.java:
8 | // static {
9 | // System.loadLibrary("nmb");
10 | // }
11 | //
12 | // Or, in MainActivity.kt:
13 | // companion object {
14 | // init {
15 | // System.loadLibrary("nmb")
16 | // }
17 | // }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/AboutProject.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb
2 |
3 | /**
4 | * Created by spq on 2022/11/9
5 | */
6 | const val aboutProject="简介\n" +
7 | "语言: kotlin\n" +
8 | "最低系统版本: android 5.0\n" +
9 | "采用最新Material You,根据系统定制app配色,快去修改系统颜色试试吧。\n" +
10 | "操作说明:首页右下角按钮分别支持左滑(弹出板块选择)、右滑(弹出设置)、上滑(回到列表顶部)、下滑(刷新)、点击(发新串)、\n" +
11 | "\n" +
12 | "技术说明:\n" +
13 | "整体项目采用MVVM+APT动态代码生成+组件化+依赖注入。\n" +
14 | "其中基础架构全部由我自己实现,参考主页中的其他项目(已发布MavenCenter,接入方式具体看wiki):\n" +
15 | "基础架构:https://github.com/yollpoll/framework/wiki/%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95\n" +
16 | "路由组建:https://github.com/yollpoll/sRouter\n" +
17 | "依赖注入采用hilt。\n" +
18 | "出于练手的目的,项目大量采用jetpack库内容,欢迎交流学习,这年头还在深入学习android的不多了好寂寞\n" +
19 | "\n" +
20 | "联动:\n" +
21 | "好多年前写的A岛客户端(肥宅岛)(停止维护):\n" +
22 | "https://github.com/yollpoll/MyApp\n" +
23 | "另有一个采用compose开发的客户端(鸽中):\n" +
24 | "https://github.com/yollpoll/nmbAndroidCompose\n" +
25 | "另有一个electron的桌面客户端(鸽中):\n" +
26 | "https://github.com/yollpoll/nmb_electron"
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/db/BaseDao.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.db
2 |
3 | import androidx.room.*
4 |
5 | @Dao
6 | interface BaseDao {
7 | @Insert(onConflict = OnConflictStrategy.REPLACE)
8 | fun insertAll(list: List)
9 |
10 | @Insert(onConflict = OnConflictStrategy.REPLACE)
11 | suspend fun insertOne(element: T)
12 |
13 | @Delete
14 | fun delete(element: T)
15 |
16 | @Delete
17 | fun deleteList(elements: List)
18 |
19 | @Delete
20 | fun deleteSome(vararg elements: T)
21 |
22 | @Update
23 | fun update(element: T)
24 |
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/db/CookieDao.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.db
2 |
3 | import androidx.room.Dao
4 | import androidx.room.Query
5 | import com.yollpoll.nmb.model.bean.CookieBean
6 |
7 | @Dao
8 | interface CookieDao : BaseDao {
9 | @Query("SELECT * FROM COOKIEBEAN ORDER BY used DESC")
10 | suspend fun queryAll(): List
11 |
12 | @Query("SELECT * FROM COOKIEBEAN WHERE USED LIKE 1 ")
13 | suspend fun queryUsed(): CookieBean?
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/db/DraftDao.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.db
2 |
3 | import androidx.room.*
4 | import com.yollpoll.nmb.model.bean.DraftBean
5 | import kotlinx.coroutines.flow.Flow
6 |
7 | /**
8 | * Created by spq on 2022/12/6
9 | */
10 | @Dao
11 | interface DraftDao {
12 | @Insert(onConflict = OnConflictStrategy.REPLACE)
13 | suspend fun insertAll(list: List)
14 |
15 | @Insert(onConflict = OnConflictStrategy.REPLACE)
16 | suspend fun insert(vararg bean: DraftBean)
17 |
18 | @Delete
19 | suspend fun delete(element: DraftBean)
20 |
21 | @Delete
22 | suspend fun deleteList(elements: List)
23 |
24 | @Delete
25 | suspend fun deleteSome(vararg elements: DraftBean)
26 |
27 | @Update
28 | suspend fun update(vararg element: DraftBean)
29 |
30 | @Query("SELECT * FROM draft ORDER BY update_time DESC")
31 | suspend fun query(): List
32 |
33 | @Query("SELECT * FROM draft ORDER BY update_time DESC")
34 | fun queryFlow(): Flow>
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/db/ForumDao.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.db
2 |
3 | import androidx.room.*
4 | import com.yollpoll.nmb.model.bean.ArticleItem
5 | import com.yollpoll.nmb.model.bean.ForumDetail
6 |
7 | /**
8 | * Created by spq on 2022/12/2
9 | */
10 | @Dao
11 | interface ForumDao {
12 | @Insert(onConflict = OnConflictStrategy.REPLACE)
13 | suspend fun insertAll(forumList: List): List
14 |
15 | @Insert(onConflict = OnConflictStrategy.IGNORE)
16 | suspend fun insertIfUnExist(forumList: List)
17 |
18 | @Update
19 | suspend fun update(vararg forumDetail: ForumDetail)
20 |
21 | @Query("SELECT * FROM forum ORDER BY sort")
22 | suspend fun queryAll(): List
23 |
24 | @Query("SELECT * FROM forum WHERE show=1 ORDER BY sort")
25 | suspend fun queryShow(): List
26 |
27 | @Query("SELECT * FROM forum WHERE id like :id")
28 | suspend fun queryForum(id: String): List
29 |
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/db/HistoryDao.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.db
2 |
3 | import androidx.room.*
4 | import com.yollpoll.nmb.model.bean.ArticleItem
5 | import com.yollpoll.nmb.model.bean.HistoryBean
6 | import com.yollpoll.nmb.model.bean.MySpeechBean
7 | import retrofit2.http.DELETE
8 |
9 | /**
10 | * Created by spq on 2022/11/11
11 | */
12 | @Dao
13 | interface HistoryDao {
14 | @Insert(onConflict = OnConflictStrategy.REPLACE)
15 | suspend fun insertAll( mySpeechBean: List)
16 |
17 | @Query("DELETE FROM historybean")
18 | suspend fun clearAll()
19 |
20 | @Query("SELECT * FROM historybean ORDER BY update_time DESC")
21 | suspend fun query(): List
22 |
23 | @Delete
24 | suspend fun delete(bean:HistoryBean)
25 |
26 | // @Query("SELECT * FROM myspeechbean")
27 | // suspend fun query(): List
28 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/db/MySpeechDao.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.db
2 |
3 | import androidx.paging.PagingSource
4 | import androidx.room.Dao
5 | import androidx.room.Insert
6 | import androidx.room.OnConflictStrategy
7 | import androidx.room.Query
8 | import com.yollpoll.nmb.model.bean.MySpeechBean
9 |
10 | @Dao
11 | interface MySpeechDao {
12 | @Insert(onConflict = OnConflictStrategy.REPLACE)
13 | suspend fun insertAll(mySpeechBean: List)
14 |
15 | @Query("DELETE FROM myspeechbean")
16 | suspend fun clearAll()
17 |
18 | @Query("SELECT * FROM myspeechbean ORDER BY id DESC")
19 | suspend fun query(): List
20 |
21 | // @Query("SELECT * FROM myspeechbean")
22 | // suspend fun query(): List
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/di/AppWidgetDI.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.di
2 |
3 | import com.yollpoll.framework.net.http.RetrofitFactory
4 | import com.yollpoll.nmb.model.repository.HomeRepository
5 | import dagger.Module
6 | import dagger.Provides
7 | import dagger.hilt.InstallIn
8 | import dagger.hilt.components.SingletonComponent
9 | import javax.inject.Singleton
10 |
11 | @InstallIn(SingletonComponent::class)//生命周期
12 | @Module
13 | class AppWidgetDI {
14 | @AppWidgetRepository
15 | @Provides
16 | @Singleton//作用域
17 | fun provideRepository(@CommonRetrofitFactory retrofitFactory: RetrofitFactory): HomeRepository =
18 | HomeRepository(retrofitFactory)
19 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/di/ArgumentsDI.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
3 | * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
4 | * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
5 | * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
6 | * Vestibulum commodo. Ut rhoncus gravida arcu.
7 | */
8 |
9 | package com.yollpoll.nmb.di
10 |
11 | import dagger.Module
12 | import dagger.hilt.InstallIn
13 | import dagger.hilt.android.components.ViewModelComponent
14 |
15 | abstract class ArgumentsDI {
16 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/di/ArticleDetailViewModelDI.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
3 | * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
4 | * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
5 | * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
6 | * Vestibulum commodo. Ut rhoncus gravida arcu.
7 | */
8 |
9 | package com.yollpoll.nmb.di
10 |
11 | import com.yollpoll.framework.net.http.RetrofitFactory
12 | import com.yollpoll.nmb.model.repository.ArticleDetailRepository
13 | import dagger.Module
14 | import dagger.Provides
15 | import dagger.hilt.InstallIn
16 | import dagger.hilt.android.components.ServiceComponent
17 | import dagger.hilt.android.components.ViewModelComponent
18 | import dagger.hilt.android.scopes.ViewModelScoped
19 | import dagger.hilt.components.SingletonComponent
20 | import javax.inject.Singleton
21 |
22 | @Module
23 | @InstallIn(SingletonComponent::class)//生命周期
24 | class ArticleDetailViewModelDI {
25 | @Singleton//作用域
26 | @Provides
27 | fun provideRepository(@CommonRetrofitFactory retrofitFactory: RetrofitFactory) =
28 | ArticleDetailRepository(retrofitFactory)
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/di/CommonDi.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.di
2 |
3 | import com.yollpoll.framework.dispatch.DispatcherManager
4 | import com.yollpoll.framework.net.http.RetrofitFactory
5 | import com.yollpoll.ilog.Ilog
6 | import com.yollpoll.log.ILogImpl
7 | import com.yollpoll.nmb.Iqr
8 | import com.yollpoll.nmb.model.repository.ArticleDetailRepository
9 | import com.yollpoll.nmb.router.DispatchClient
10 | import com.yollpoll.qrlib.QrUtils
11 | import dagger.Binds
12 | import dagger.Module
13 | import dagger.Provides
14 | import dagger.hilt.InstallIn
15 | import dagger.hilt.components.SingletonComponent
16 | import javax.inject.Singleton
17 |
18 | /**
19 | * Created by spq on 2022/1/10
20 | */
21 | @Module
22 | @InstallIn(SingletonComponent::class)
23 | class DispatchClientDi {
24 |
25 | @Provides
26 | fun getManager(): DispatcherManager {
27 | return DispatchClient.manager
28 | }
29 | }
30 |
31 | @Module
32 | @InstallIn(SingletonComponent::class)
33 | abstract class LogDi {
34 | @Binds
35 | abstract fun bindILog(ilog: ILogImpl): Ilog
36 | }
37 |
38 | @Module
39 | @InstallIn(SingletonComponent::class)//生命周期
40 | abstract class QrDi {
41 | @Binds
42 | abstract fun bindILog(iqr: QrUtils): Iqr
43 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/di/DBModuleDI.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.di
2 |
3 | import com.yollpoll.framework.net.http.RetrofitFactory
4 | import com.yollpoll.nmb.db.MainDB
5 | import com.yollpoll.nmb.net.launcherRetrofitFactory
6 | import dagger.Module
7 | import dagger.Provides
8 | import dagger.hilt.InstallIn
9 | import dagger.hilt.android.scopes.ViewModelScoped
10 | import dagger.hilt.components.SingletonComponent
11 | import javax.inject.Singleton
12 |
13 | @Module
14 | @InstallIn(SingletonComponent::class)
15 | class DBModuleDI {
16 | @Singleton
17 | @Provides
18 | fun provideDB(): MainDB {
19 | return MainDB.getInstance()
20 | }
21 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/di/DiAnnotation.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.di
2 |
3 | import javax.inject.Qualifier
4 |
5 | //retrofitFactory
6 |
7 | @Qualifier
8 | @Retention(AnnotationRetention.BINARY)
9 | annotation class CommonRetrofitFactory
10 |
11 | @Qualifier
12 | @Retention(AnnotationRetention.BINARY)
13 | annotation class LauncherRetrofitFactory
14 |
15 | //repository
16 |
17 | @Qualifier
18 | @Retention(AnnotationRetention.BINARY)
19 | annotation class LauncherRepositoryAnnotation
20 |
21 | @Qualifier
22 | @Retention(AnnotationRetention.BINARY)
23 | annotation class HomeRepositoryAnnotation
24 |
25 | @Qualifier
26 | @Retention(AnnotationRetention.BINARY)
27 | annotation class ArticleDetailAnnotation
28 |
29 | @Qualifier
30 | @Retention(AnnotationRetention.BINARY)
31 | annotation class AppWidgetRepository
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/di/HomeViewModelDI.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.di
2 |
3 | import com.yollpoll.framework.net.http.RetrofitFactory
4 | import com.yollpoll.nmb.model.repository.HomeRepository
5 | import dagger.Module
6 | import dagger.Provides
7 | import dagger.hilt.InstallIn
8 | import dagger.hilt.android.components.ViewModelComponent
9 | import dagger.hilt.android.scopes.ViewModelScoped
10 |
11 | @InstallIn(ViewModelComponent::class)
12 | @Module
13 | class HomeModel {
14 | @Provides
15 | @ViewModelScoped
16 | fun provideRepository(@CommonRetrofitFactory retrofitFactory: RetrofitFactory): HomeRepository =
17 | HomeRepository(retrofitFactory)
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/di/LauncherViewModelDI.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.di
2 |
3 | import com.yollpoll.framework.net.http.RetrofitFactory
4 | import com.yollpoll.nmb.model.repository.LauncherRepository
5 | import dagger.Module
6 | import dagger.Provides
7 | import dagger.hilt.InstallIn
8 | import dagger.hilt.android.components.ViewModelComponent
9 | import dagger.hilt.android.scopes.ViewModelScoped
10 |
11 | @Module
12 | @InstallIn(ViewModelComponent::class)
13 | class LauncherViewModelDI {
14 | @ViewModelScoped
15 | @Provides
16 | fun provideRepository(@LauncherRetrofitFactory retrofitFactory: RetrofitFactory) =
17 | LauncherRepository(retrofitFactory)
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/di/NetModuleDI.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.di
2 |
3 | import com.yollpoll.arch.log.LogUtils
4 | import com.yollpoll.framework.net.http.RetrofitFactory
5 | import com.yollpoll.framework.net.http.RetrofitIntercept
6 | import com.yollpoll.nmb.net.BASE_URL
7 | import com.yollpoll.nmb.net.CoverImgInterceptor
8 | import com.yollpoll.nmb.net.commonRetrofitFactory
9 | import com.yollpoll.nmb.net.launcherRetrofitFactory
10 | import dagger.Module
11 | import dagger.Provides
12 | import dagger.hilt.InstallIn
13 | import dagger.hilt.android.components.ViewModelComponent
14 | import dagger.hilt.android.scopes.ViewModelScoped
15 | import dagger.hilt.components.SingletonComponent
16 | import okhttp3.OkHttpClient
17 | import retrofit2.Retrofit
18 | import javax.inject.Singleton
19 |
20 | @Module
21 | @InstallIn(SingletonComponent::class)//生命周期
22 | class NetModuleDI {
23 |
24 | @Singleton
25 | @Provides
26 | @LauncherRetrofitFactory
27 | fun provideLauncherRetrofitFactory(): RetrofitFactory {
28 | return launcherRetrofitFactory
29 | }
30 |
31 | @Singleton
32 | @Provides
33 | @CommonRetrofitFactory
34 | fun provideCommonRetrofitFactory(): RetrofitFactory {
35 | return commonRetrofitFactory
36 | }
37 |
38 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/di/RepositoryDI.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.di
2 |
3 | import com.yollpoll.nmb.model.repository.ArticleDetailRepository
4 | import com.yollpoll.nmb.model.repository.HomeRepository
5 | import com.yollpoll.nmb.model.repository.IRepository
6 | import com.yollpoll.nmb.model.repository.LauncherRepository
7 | import dagger.Binds
8 | import dagger.Module
9 | import dagger.hilt.InstallIn
10 | import dagger.hilt.android.components.ViewModelComponent
11 |
12 | //@Module
13 | //@InstallIn(ViewModelComponent::class)
14 | //abstract class LauncherRepositoryDI {
15 | // @Binds
16 | // @LauncherRepositoryAnnotation
17 | // abstract fun provideRepository(launcherRepository: LauncherRepository): IRepository
18 | //
19 | // @Binds
20 | // @HomeRepositoryAnnotation
21 | // abstract fun provideHomeRepository(launcherRepository: HomeRepository): IRepository
22 | //
23 | // @Binds
24 | // @ArticleDetailAnnotation
25 | // abstract fun provideArticleDetailRepository(repository: ArticleDetailRepository): IRepository
26 | //}
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/model/bean/Announcement.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.model.bean
2 |
3 | import com.squareup.moshi.JsonClass
4 |
5 | @JsonClass(generateAdapter = true)
6 | class Announcement(val content: String, val date: Long, val enable: Boolean) {
7 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/model/bean/Article.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.model.bean
2 |
3 | import androidx.room.*
4 | import com.squareup.moshi.Json
5 | import com.squareup.moshi.JsonClass
6 | import java.sql.Timestamp
7 |
8 |
9 | //class Article : ArrayList()
10 | typealias Article = ArrayList
11 |
12 | @Entity
13 | @JsonClass(generateAdapter = true)
14 | data class ArticleItem(
15 | var admin: String,
16 | var content: String,
17 | var email: String?,
18 | @ColumnInfo(name = "ext") var ext: String,
19 | @PrimaryKey var id: String,
20 | @ColumnInfo(name = "img") var img: String,
21 | var name: String,
22 | var now: String,
23 | var ReplyCount: String?,
24 | var title: String,
25 | var user_hash: String,
26 | var master: String?,//是否是发帖人
27 | var page: Int = 1,
28 | var sage: Int,//吃我世嘉
29 | var Hide: Int,
30 | var replyTo: String?,//当前回复的串的id
31 | ) {
32 | @Ignore
33 | var Replies: List? = null
34 |
35 | @Ignore
36 | var tagColor: Int? = null//标记
37 |
38 | @Ignore
39 | var index: Int? = null//第x条回复
40 |
41 |
42 | }
43 |
44 | @JsonClass(generateAdapter = true)
45 | data class ImgTuple(
46 | @ColumnInfo(name = "img") val img: String,
47 | @ColumnInfo(name = "ext") val ext: String,
48 | @ColumnInfo(name = "id") val id: String,
49 | )
50 |
51 | data class PageItem(@ColumnInfo(name = "page") val page: Int)
52 |
53 | @Entity
54 | data class ShieldArticle(@PrimaryKey val articleId: String)//屏蔽列表
55 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/model/bean/CookieBean.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.model.bean
2 |
3 | import androidx.room.Entity
4 | import androidx.room.PrimaryKey
5 | import com.squareup.moshi.Json
6 | import com.squareup.moshi.JsonClass
7 |
8 | @Entity
9 | @JsonClass(generateAdapter = true)
10 | data class CookieBean(
11 | var cookie: String,
12 | @PrimaryKey(autoGenerate = false) var name: String,
13 | var used: Int = 0//0未使用,1使用中
14 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/model/bean/DraftBean.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.model.bean
2 |
3 | import androidx.room.ColumnInfo
4 | import androidx.room.Entity
5 | import androidx.room.PrimaryKey
6 | import com.squareup.moshi.JsonClass
7 |
8 | /**
9 | * Created by spq on 2022/12/6
10 | */
11 | @JsonClass(generateAdapter = true)
12 | @Entity(tableName = "draft")
13 | data class DraftBean(
14 | var reply: String?,
15 | val fid: String,
16 | @ColumnInfo(name = "f_name")
17 | val fName: String,//板块名称
18 | val mask: String,
19 | val email: String?,
20 | @PrimaryKey(autoGenerate = true)
21 | val id: Int? = 0,
22 | val title: String?,
23 | val content: String,
24 | @ColumnInfo(name = "update_time") val updateTime: Long,
25 | val img: String?
26 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/model/bean/Fourm.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.model.bean
2 |
3 | import androidx.room.Entity
4 | import androidx.room.PrimaryKey
5 | import com.squareup.moshi.JsonClass
6 |
7 | class ForumList : ArrayList()
8 |
9 |
10 | //板块
11 | @JsonClass(generateAdapter = true)
12 | data class Forum(
13 | val forums: List,
14 | val id: String,
15 | val name: String,
16 | val sort: String,
17 | val status: String
18 | )
19 |
20 | //详细版本
21 | @JsonClass(generateAdapter = true)
22 | @Entity(tableName = "forum")
23 | data class ForumDetail(
24 | var createdAt: String?,
25 | var fgroup: String?,
26 | @PrimaryKey
27 | val id: String,
28 | var interval: String?,
29 | var msg: String,
30 | var name: String,
31 | var showName: String?,
32 | var sort: String?,
33 | var status: String?,
34 | var updateAt: String?,
35 | var show: Int = 1
36 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/model/bean/HistoryBean.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.model.bean
2 |
3 | import androidx.room.ColumnInfo
4 | import androidx.room.Entity
5 | import androidx.room.PrimaryKey
6 | import com.squareup.moshi.JsonClass
7 |
8 | /**
9 | * Created by spq on 2022/11/11
10 | */
11 | @Entity
12 | data class HistoryBean(
13 | val admin: String,
14 | val content: String,
15 | val email: String?,
16 | @PrimaryKey
17 | val id: Int,
18 | val name: String,
19 | var now: String,
20 | val resto: String?,
21 | val sage: String?,
22 | val title: String,
23 | val user_hash: String,
24 | @ColumnInfo(name = "update_time",defaultValue = "'CURRENT_TIMESTAMP'")
25 | var updateTime: Long,
26 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/model/bean/MySpeechBean.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.model.bean
2 |
3 | import androidx.room.Entity
4 | import androidx.room.PrimaryKey
5 | import com.squareup.moshi.JsonClass
6 |
7 | @JsonClass(generateAdapter = true)
8 | @Entity
9 | data class MySpeechBean(
10 | val admin: Int,
11 | val content: String,
12 | val email: String,
13 | @PrimaryKey
14 | val id: Int,
15 | val name: String,
16 | val now: String,
17 | val resto: Int,
18 | val sage: Int,
19 | val title: String,
20 | val user_hash: String
21 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/model/bean/SettingBean.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.model.bean
2 |
3 | import com.yollpoll.skin.SkinTheme
4 |
5 | /**
6 | * Created by spq on 2022/11/21
7 | */
8 | data class SettingBean(
9 | val uiTheme: SkinTheme,
10 | val darkMod: DarkMod,
11 | val collectionId: String,
12 | val noImage: Boolean,
13 | val noCookie: Boolean,
14 | val thumbBigImg: Boolean,
15 | )
16 |
17 | enum class DarkMod(name: String) {
18 | DARK("黑暗"), LIGHT("光明"), AUTO("自动")
19 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/model/repository/CookieRepository.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.model.repository
2 |
3 | import com.yollpoll.nmb.db.MainDB
4 | import com.yollpoll.nmb.model.bean.CookieBean
5 | import kotlinx.coroutines.Dispatchers
6 | import kotlinx.coroutines.withContext
7 | import javax.inject.Inject
8 |
9 | class CookieRepository @Inject constructor(val db: MainDB) : IRepository {
10 | suspend fun queryCookies(): List = withContext(Dispatchers.IO) {
11 | db.getCookieDao().queryAll()
12 | }
13 |
14 | suspend fun insertCookie(vararg cookie: CookieBean) = withContext(Dispatchers.IO) {
15 | db.getCookieDao().insertAll(cookie.toList())
16 | }
17 |
18 | suspend fun updateCookie(cookie: CookieBean) = withContext(Dispatchers.IO) {
19 | db.getCookieDao().update(cookie)
20 | }
21 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/model/repository/DraftRepository.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.model.repository
2 |
3 | import com.yollpoll.nmb.db.MainDB
4 | import com.yollpoll.nmb.model.bean.DraftBean
5 | import kotlinx.coroutines.flow.Flow
6 | import javax.inject.Inject
7 |
8 | /**
9 | * Created by spq on 2022/12/6
10 | */
11 | class DraftRepository @Inject constructor(val db: MainDB) : IRepository {
12 | suspend fun getDrafts(): List {
13 | return db.getDraftDao().query()
14 | }
15 |
16 | fun getDraftFlow(): Flow> {
17 | return db.getDraftDao().queryFlow()
18 | }
19 |
20 | suspend fun delDraft(bean: DraftBean) {
21 | db.getDraftDao().delete(bean)
22 | }
23 |
24 | suspend fun insetDraft(vararg bean: DraftBean) {
25 | db.getDraftDao().insert(*bean)
26 | }
27 |
28 | suspend fun updateDraft(vararg bean: DraftBean) {
29 | db.getDraftDao().update(*bean)
30 | }
31 |
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/model/repository/IRepository.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.model.repository
2 |
3 | interface IRepository {
4 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/model/repository/LauncherRepository.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.model.repository
2 |
3 | import android.util.Log
4 | import com.yollpoll.framework.net.http.RetrofitFactory
5 | import com.yollpoll.nmb.TAG
6 | import com.yollpoll.nmb.di.LauncherRetrofitFactory
7 | import com.yollpoll.nmb.net.DIRECT_BASE_URL
8 | import com.yollpoll.nmb.net.HttpService
9 | import com.yollpoll.nmb.net.realUrl
10 | import java.lang.Exception
11 | import javax.inject.Inject
12 |
13 |
14 | class LauncherRepository @Inject constructor(
15 | @LauncherRetrofitFactory val retrofitFactory: RetrofitFactory
16 | ) : IRepository {
17 | private val service by lazy {
18 | retrofitFactory.createService(HttpService::class.java)
19 | }
20 |
21 | @Throws(Exception::class)
22 | suspend fun loadRealUrl() {
23 | try {
24 | val url = service.getRealUrl()
25 | realUrl = url[0]
26 | Log.d(TAG, "loadRealUrl: $realUrl")
27 | } catch (e: Exception) {
28 | realUrl = DIRECT_BASE_URL
29 | throw Exception("获取真实url失败:${e.message}")
30 | }
31 | }
32 |
33 | suspend fun getForumList() = service.getForumList()
34 |
35 | //获取封面真实地址
36 | suspend fun refreshCover() = service.refreshCover()
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/net/Cookie.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.net
2 |
3 | import androidx.datastore.preferences.preferencesDataStore
4 | import com.yollpoll.base.logI
5 | import com.yollpoll.framework.extensions.getBean
6 | import com.yollpoll.nmb.App
7 | import com.yollpoll.nmb.model.bean.CookieBean
8 | import kotlinx.coroutines.GlobalScope
9 | import kotlinx.coroutines.async
10 | import kotlinx.coroutines.launch
11 | import kotlinx.coroutines.runBlocking
12 | import okhttp3.Cookie
13 | import okhttp3.CookieJar
14 | import okhttp3.HttpUrl
15 | import java.net.URL
16 |
17 | val cookieStore = hashMapOf>()
18 |
19 | class LocalCookieJar : CookieJar {
20 | override fun saveFromResponse(url: HttpUrl, cookies: MutableList) {
21 | cookieStore[url.host()] = cookies
22 | }
23 |
24 | override fun loadForRequest(url: HttpUrl): MutableList {
25 | val builder = Cookie.Builder()
26 | val list = arrayListOf()
27 | App.INSTANCE.cookie?.run {
28 | "find cookie: ${this.name}".logI()
29 | val cookie =
30 | builder.name("userhash").value(this.cookie).domain(url.host()).build()
31 | list.add(cookie)
32 | }
33 | return list
34 | }
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/net/CoverImgInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.net
2 |
3 | import android.util.Log
4 | import com.yollpoll.base.logI
5 | import okhttp3.Interceptor
6 | import okhttp3.Response
7 |
8 | private const val TAG = "CoverImgInterceptor"
9 |
10 | class CoverImgInterceptor : Interceptor {
11 | override fun intercept(chain: Interceptor.Chain): Response {
12 | try {
13 | val orgUrl = chain.request().url().toString()
14 | "url:${orgUrl}".logI()
15 | val response = chain.proceed(chain.request())
16 | val realUrl = response.request().url().toString()
17 | if (orgUrl == COVER) {
18 | Log.d(TAG, "intercept: realUrl$realUrl")
19 | //拦截到封面请求
20 | realCover = realUrl
21 | }
22 | return response
23 | } catch (e: Exception) {
24 |
25 | }
26 | return chain.proceed(chain.request())
27 | }
28 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/net/HttpServiceFactory.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.net
2 |
3 | import com.yollpoll.arch.log.LogUtils
4 | import com.yollpoll.framework.extensions.shortToast
5 | import com.yollpoll.framework.net.http.RetrofitFactory
6 | import com.yollpoll.framework.net.http.RetrofitIntercept
7 | import okhttp3.OkHttpClient
8 | import retrofit2.Retrofit
9 |
10 | val launcherRetrofitFactory by lazy {
11 | RetrofitFactory(object : RetrofitIntercept {
12 | override fun baseUrl(): String {
13 | return BASE_URL
14 | }
15 |
16 | override fun okHttpClient(client: OkHttpClient) {
17 | }
18 |
19 | override fun okHttpClientBuilder(builder: OkHttpClient.Builder) {
20 | builder.addInterceptor(CoverImgInterceptor())
21 |
22 | }
23 |
24 |
25 | override fun retrofit(retrofit: Retrofit) {
26 | }
27 |
28 | override fun retrofitBuilder(builder: Retrofit.Builder) {
29 | // builder.addConverterFactory(MoshiConverterFactory.create())
30 | }
31 |
32 | })
33 | }
34 | val commonRetrofitFactory by lazy {
35 | RetrofitFactory(object : RetrofitIntercept {
36 | override fun baseUrl(): String {
37 | return BASE_URL
38 | }
39 |
40 | override fun okHttpClient(client: OkHttpClient) {
41 | }
42 |
43 | override fun okHttpClientBuilder(builder: OkHttpClient.Builder) {
44 | builder.addInterceptor(LoggerInterceptor())
45 | builder.addInterceptor(CoverImgInterceptor())
46 | builder.addInterceptor(NMBInterceptor())
47 | builder.cookieJar(LocalCookieJar())
48 |
49 | }
50 |
51 |
52 | override fun retrofit(retrofit: Retrofit) {
53 | }
54 |
55 | override fun retrofitBuilder(builder: Retrofit.Builder) {
56 | // builder.addConverterFactory(MoshiConverterFactory.create())
57 | }
58 |
59 | })
60 |
61 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/net/NMBInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.net
2 |
3 | import com.yollpoll.nmb.APP_ID
4 | import com.yollpoll.nmb.USER_AGENT
5 | import okhttp3.Headers
6 | import okhttp3.Interceptor
7 | import okhttp3.Request
8 | import okhttp3.Response
9 |
10 | class NMBInterceptor : Interceptor {
11 | //header
12 | private val headers = hashMapOf(
13 | "User-Agent" to USER_AGENT
14 | )
15 | private val commonParams = hashMapOf(
16 | "appid" to APP_ID
17 | )
18 |
19 | override fun intercept(chain: Interceptor.Chain): Response {
20 | val oldRequest = chain.request()
21 | val builder = oldRequest.newBuilder()
22 | injectParams(oldRequest, builder, commonParams)
23 | val newRequest = builder.headers(Headers.of(headers)).build()
24 | return chain.proceed(newRequest)
25 | }
26 |
27 |
28 | //注入参数
29 | private fun injectParams(
30 | request: Request,
31 | builder: Request.Builder,
32 | params: Map
33 | ) {
34 | val httpUrlBuilder = request.url().newBuilder()
35 | params.forEach {
36 | httpUrlBuilder.addQueryParameter(it.key, it.value)
37 | }
38 | builder.url(httpUrlBuilder.build())
39 | }
40 |
41 |
42 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/net/Url.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.net
2 |
3 |
4 | const val DOMAIN = "google.com"
5 | const val BASE_URL = "https://www.nmbxd1.com/"
6 | const val DIRECT_BASE_URL = "https://adnmb3.com/"//重定向以后的url,应该动态获取
7 |
8 | const val ROOT_URL = "Api/backupUrl"//重定向获取根url
9 |
10 | const val CDN_URL = "Api/getCdnPath"//图片cdn地址
11 | const val COVER = "http://nmb.ovear.info/h.php"//封面地址,会重定向
12 | var realCover = ""//封面图片重定向以后的真实地址
13 | const val ANNOUNCEMENT = "http://nmb.ovear.info/nmb-notice.json"//公告
14 | const val IMG_THUMB_URL = "/thumb/"
15 | const val IMG_URL = "/image/"
16 |
17 | //获取板块列表
18 | const val FORUM_LIST = "Api/getForumList"
19 |
20 | //获取串
21 | const val GET_ARTICLE = "Api/showf/"
22 | const val GET_CHILD_ARTICLE = "Api/thread"
23 |
24 | const val NEW_THREAD: String = "Home/Forum/doPostThread.html"
25 | const val REPLY_THREAD: String = "Home/Forum/doReplyThread.html"
26 |
27 | //查看订阅
28 | const val COLLECTION: String = "/Api/feed"
29 | const val ADD_COLLECTION: String = "/Api/addFeed"
30 | const val DEL_COLLECTION: String = "/Api/delFeed"
31 |
32 | //时间线
33 | // public static final String TIME_LINE = "Api/timeline";
34 | const val TIME_LINE: String = "Api/timeline/"
35 | const val TIME_LINE_ID = "-1"
36 |
37 | var realUrl: String? = null//重定向以后获取到的根url
38 |
39 | var imagHead = "https://image.nmb.best"//应该动态获取
40 | var imgUrl = imagHead + IMG_URL
41 | var imgThumbUrl = imagHead + IMG_THUMB_URL
42 |
43 | //发言历史
44 | const val SPEAKING_HISTORY = "/Api/getLastPost"
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/net/Utils.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.net
2 |
3 | import com.yollpoll.base.logI
4 | import okhttp3.MediaType
5 | import okhttp3.MultipartBody
6 | import okhttp3.RequestBody
7 | import java.io.File
8 |
9 | /**
10 | * 根据文件创建requestbody
11 | *
12 | * @param file
13 | * @return
14 | */
15 | fun getRequestBody(file: File?): RequestBody? {
16 | if (file == null) {
17 | return null
18 | }
19 | // 创建 RequestBody,用于封装构建RequestBody
20 | return RequestBody.create(MediaType.parse("image/*"), file)
21 | }
22 |
23 | /**
24 | * 根据文件创建requestbody
25 | *
26 | * @param content
27 | * @return
28 | */
29 | fun getRequestBody(content: String?): RequestBody? {
30 | if (content == null) {
31 | return null
32 | }
33 | "getReqbody ".logI()
34 | // 创建 RequestBody,用于封装构建RequestBody
35 | return RequestBody.create(MediaType.parse("text/plain"), content)
36 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/router/Route.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.router
2 |
3 | /**
4 | * Created by spq on 2022/6/27
5 | */
6 | const val ROUTE_LAUNCHER = "native://nmb?module=launcher"
7 | const val ROUTE_HOME = "native://nmb?module=home"
8 | const val ROUTE_THREAD_DETAIL = "native://nmb?module=thread_detail"
9 | const val ROUTE_IMAGE = "native://nmb?module=img"
10 | const val ROUTE_THREAD_IMAGE = "native://nmb?module=thread_img"
11 | const val ROUTE_COOKIE="native://nmb?module=cookie"
12 | //const val ROUTE_QR="native://nmb?module=qrcode"
13 | const val ROUTE_QR="native://qrlib?module=qrcode"
14 | const val ROUTE_NEW_THREAD="native://nmb?module=new_thread"
15 | const val ROUTE_CHOOSE_TAG="native://nmb?module=choose_tag"
16 | const val ROUTE_COLLECTION="native://nmb?module=collection"
17 | const val ROUTE_MY_SPEECH="native://nmb?module=my_speech"
18 | const val ROUTE_DRAW="native://nmb?module=draw"
19 | const val ROUTE_AUTHOR="native://nmb?module=author"
20 | const val ROUTE_SETTING="native://nmb?module=setting"
21 | const val ROUTE_HISTORY="native://nmb?module=history"
22 | const val ROUTE_SHIELD_LIST="native://nmb?module=shield"
23 | const val ROUTE_FORUM_SETTING="native://nmb?module=forum_setting"//板块配置
24 | const val ROUTE_DRAFT="native://nmb?module=draft"//草稿箱
25 | const val ROUTE_PAY="native://nmb?module=pay"//打赏
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/view/widgets/BindAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.view.widgets
2 |
3 | import android.widget.ImageView
4 | import androidx.databinding.BindingAdapter
5 | import com.bumptech.glide.Glide
6 | import com.yollpoll.nmb.net.imgThumbUrl
7 | import com.yollpoll.nmb.net.imgUrl
8 |
9 | class BindAdapter {
10 | companion object {
11 | @BindingAdapter(value = ["thumbUrl"], requireAll = true)
12 | fun thumbUrl(view: ImageView, url: String) {
13 | //图片加载
14 | Glide.with(view.context)
15 | .asBitmap()
16 | .apply(getCommonGlideOptions(view.context))
17 | .load(imgThumbUrl + url)
18 | .into(view)
19 | }
20 |
21 | @BindingAdapter(value = ["imgUrl"], requireAll = true)
22 | fun realImgUrl(view: ImageView, url: String) {
23 | //图片加载
24 | Glide.with(view.context)
25 | .asBitmap()
26 | .apply(getCommonGlideOptions(view.context))
27 | .load(imgUrl + url)
28 | .into(view)
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/view/widgets/ChangeBurshWidthView.java:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.view.widgets;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Paint;
6 | import android.support.annotation.Nullable;
7 | import android.util.AttributeSet;
8 | import android.view.View;
9 |
10 | import com.yollpoll.nmb.R;
11 |
12 |
13 | /**
14 | * Created by 鹏祺 on 2017/6/22.
15 | */
16 |
17 | public class ChangeBurshWidthView extends View {
18 | private Paint mPaint;
19 |
20 | public ChangeBurshWidthView(Context context) {
21 | super(context);
22 | init();
23 | }
24 |
25 | public ChangeBurshWidthView(Context context, @Nullable AttributeSet attrs) {
26 | super(context, attrs);
27 | init();
28 | }
29 |
30 | public ChangeBurshWidthView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
31 | super(context, attrs, defStyleAttr);
32 | init();
33 | }
34 |
35 | public void setWidth(int width){
36 | mPaint.setStrokeWidth(width);
37 | postInvalidate();
38 | }
39 | private void init() {
40 | mPaint = new Paint();
41 | mPaint.setColor(getResources().getColor(R.color.black));
42 | mPaint.setAntiAlias(true);
43 | mPaint.setStrokeWidth(20);
44 | mPaint.setDither(true);
45 | mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
46 | mPaint.setStrokeCap(Paint.Cap.ROUND);
47 | }
48 |
49 | @Override
50 | protected void onDraw(Canvas canvas) {
51 | super.onDraw(canvas);
52 | canvas.drawLine(0 + getPaddingLeft(), (getMeasuredHeight() - getPaddingTop() - getPaddingBottom()) / 2, getMeasuredWidth() - getPaddingRight(),
53 | (getMeasuredHeight() - getPaddingTop() - getPaddingBottom()) / 2, mPaint);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/view/widgets/ImportCollectionDialog.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.view.widgets
2 |
3 | import android.app.Dialog
4 | import android.content.Context
5 | import android.view.WindowManager
6 | import com.yollpoll.base.NMBDialog
7 | import com.yollpoll.framework.extensions.dp2px
8 | import com.yollpoll.nmb.R
9 | import com.yollpoll.nmb.databinding.DialogImportCollectionBinding
10 |
11 | /**
12 | * Created by spq on 2022/11/8
13 | */
14 | class ImportCollectionDialog(
15 | private val mContext: Context?,
16 | private val onOk: ((String?) -> Unit)? = null
17 | ) :
18 | NMBDialog(mContext) {
19 | public var no: String? = null
20 |
21 | override fun getLayoutId() = R.layout.dialog_import_collection
22 |
23 | override fun createDialog(context: Context?) = Dialog(mContext)
24 |
25 | override fun onInit(dialog: Dialog?, binding: DialogImportCollectionBinding?) {
26 | super.onInit(dialog, binding)
27 | binding?.dialog = this
28 | }
29 |
30 | override fun onDialogShow(dialog: Dialog) {
31 | super.onDialogShow(dialog)
32 | val lp: WindowManager.LayoutParams = WindowManager.LayoutParams()
33 |
34 | lp.copyFrom(dialog.window?.attributes)
35 |
36 | lp.width = mContext.dp2px(320F).toInt()
37 |
38 | lp.height = mContext.dp2px(200F).toInt()
39 |
40 | lp.horizontalMargin
41 |
42 | dialog.window?.attributes = lp
43 | }
44 |
45 | fun onOkClick() {
46 | onOk?.invoke(no)
47 | this.dismiss()
48 | }
49 |
50 | fun onCancelClick() {
51 | this.dismiss()
52 | }
53 |
54 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/view/widgets/InputDialog.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.view.widgets
2 |
3 | import android.app.Dialog
4 | import android.content.Context
5 | import android.view.WindowManager
6 | import com.yollpoll.base.NMBDialog
7 | import com.yollpoll.framework.extensions.dp2px
8 | import com.yollpoll.nmb.R
9 | import com.yollpoll.nmb.databinding.DialogImportCollectionBinding
10 | import com.yollpoll.nmb.databinding.DialogInputBinding
11 |
12 | /**
13 | * Created by spq on 2022/11/22
14 | */
15 | class InputDialog(
16 | private val mContext: Context,
17 | val title: String,
18 | val hint: String,
19 | var content: String? = null,
20 | private val onOk: ((String?) -> Unit)? = null
21 |
22 | ) : NMBDialog(mContext) {
23 |
24 | override fun getLayoutId() = R.layout.dialog_input
25 |
26 | override fun createDialog(context: Context?) = Dialog(mContext)
27 |
28 | override fun onInit(dialog: Dialog?, binding: DialogInputBinding?) {
29 | super.onInit(dialog, binding)
30 | binding?.dialog = this
31 | }
32 |
33 | override fun onDialogShow(dialog: Dialog) {
34 | super.onDialogShow(dialog)
35 | val lp: WindowManager.LayoutParams = WindowManager.LayoutParams()
36 |
37 | lp.copyFrom(dialog.window?.attributes)
38 |
39 | lp.width = mContext.dp2px(320F).toInt()
40 |
41 | lp.height = mContext.dp2px(200F).toInt()
42 |
43 | lp.horizontalMargin
44 |
45 | dialog.window?.attributes = lp
46 | }
47 |
48 | fun onOkClick() {
49 | onOk?.invoke(content)
50 | this.dismiss()
51 | }
52 |
53 | fun onCancelClick() {
54 | this.dismiss()
55 | }
56 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/view/widgets/MyFloatingMenu.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.view.widgets
2 |
3 | class MyFloatingMenu {
4 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/view/widgets/SelectPageDialog.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.view.widgets
2 |
3 | import android.app.Dialog
4 | import android.content.Context
5 | import android.widget.SeekBar
6 | import androidx.appcompat.app.AlertDialog
7 | import androidx.core.app.DialogCompat
8 | import com.yollpoll.base.NMBDialog
9 | import com.yollpoll.framework.widgets.BaseDialog
10 | import com.yollpoll.nmb.R
11 | import com.yollpoll.nmb.databinding.DialogSelectPageBinding
12 |
13 | class SelectPageDialog(
14 | private val cur: Int,
15 | private val max: Int,
16 | private val context: Context,
17 | private val onSelected: ((Int) -> Unit)? = null
18 | ) :
19 | NMBDialog(context) {
20 | var selectPage: Int = cur
21 | override fun getLayoutId() = R.layout.dialog_select_page
22 |
23 | override fun createDialog(context: Context) = Dialog(context)
24 |
25 | override fun onInit(dialog: Dialog?, binding: DialogSelectPageBinding) {
26 | binding.max = max
27 | binding.cur = cur
28 | binding.selected = selectPage
29 | binding.seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
30 | override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
31 | selectPage = progress + 1
32 | binding.selected = selectPage
33 | binding.executePendingBindings()
34 | }
35 |
36 | override fun onStartTrackingTouch(seekBar: SeekBar?) {
37 | }
38 |
39 | override fun onStopTrackingTouch(seekBar: SeekBar?) {
40 | }
41 | })
42 | binding.executePendingBindings()
43 | binding.btnOk.setOnClickListener {
44 | onSelected?.invoke(selectPage)
45 | this.dismiss()
46 | }
47 | binding.btnCancel.setOnClickListener {
48 | this.dismiss()
49 | }
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/view/widgets/emoji/PicEmojiAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.view.widgets.emoji
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import android.widget.ImageView
7 | import androidx.recyclerview.widget.RecyclerView
8 | import com.yollpoll.nmb.R
9 |
10 | /**
11 | * Created by 鹏祺 on 2017/6/15.
12 | */
13 | class PicEmojiAdapter(
14 | private val list: List,
15 | private val onItemClick: ((View, Int) -> Unit)?
16 | ) :
17 | RecyclerView.Adapter() {
18 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
19 | val view =
20 | LayoutInflater.from(parent.context).inflate(R.layout.item_pic_emoji, parent, false)
21 | return ViewHolder(view)
22 | }
23 |
24 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {
25 | val item = list[position]
26 | holder.imgPicEmoji.setImageResource(item)
27 | holder.imgPicEmoji.setOnClickListener { v ->
28 | onItemClick?.invoke(
29 | v,
30 | position
31 | )
32 | }
33 | }
34 |
35 | override fun getItemCount(): Int {
36 | return list.size
37 | }
38 |
39 | inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
40 | var imgPicEmoji: ImageView
41 |
42 | init {
43 | imgPicEmoji = itemView.findViewById(R.id.img_pic_emoji) as ImageView
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yollpoll/nmb/view/widgets/emoji/WordEmojiAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb.view.widgets.emoji
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import android.widget.TextView
7 | import androidx.recyclerview.widget.RecyclerView
8 | import com.yollpoll.nmb.R
9 |
10 | /**
11 | * Created by 鹏祺 on 2017/6/15.
12 | */
13 | class WordEmojiAdapter(
14 | private val list: List,
15 | private val onItemClick: ((View, Int) -> Unit)?
16 | ) :
17 | RecyclerView.Adapter() {
18 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
19 | val view =
20 | LayoutInflater.from(parent.context).inflate(R.layout.item_word_emoji, parent, false)
21 | return ViewHolder(view)
22 | }
23 |
24 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {
25 | val item = list[position]
26 | holder.tvWordEomji.text = item
27 | holder.tvWordEomji.setOnClickListener { v ->
28 | onItemClick?.invoke(
29 | v,
30 | holder.adapterPosition
31 | )
32 | }
33 | }
34 |
35 | override fun getItemCount(): Int {
36 | return list.size
37 | }
38 |
39 | inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
40 | var tvWordEomji: TextView
41 |
42 | init {
43 | tvWordEomji = itemView.findViewById(R.id.tv_word_emoji) as TextView
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/app/src/main/res/anim/new_thread_anim.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/new_thread_anim_close.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/new_thread_layout_anim.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-night/ic_checked.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/drawable-v24/ic_logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/shape_new_thread_tag.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_add_cookie.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_checked.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ripple_forum.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | -
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ripple_forum_hide.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | -
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ripple_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 | -
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ripple_widget.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 | -
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_cookie_color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_drawer.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_line.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_right_drawer.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_tag.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_collection.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
15 |
16 |
17 |
21 |
22 |
26 |
27 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_draft.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
15 |
16 |
17 |
22 |
23 |
28 |
29 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_forum_setting.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
14 |
15 |
16 |
20 |
21 |
26 |
27 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_history.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
15 |
16 |
17 |
22 |
23 |
27 |
28 |
33 |
34 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
14 |
15 |
16 |
20 |
21 |
26 |
27 |
33 |
34 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
10 |
13 |
14 |
15 |
20 |
21 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_my_speech.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
15 |
16 |
17 |
20 |
21 |
25 |
26 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_qr.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
11 |
12 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_shield.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
15 |
16 |
17 |
21 |
22 |
26 |
27 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_thread_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
14 |
15 |
16 |
20 |
21 |
26 |
27 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_web.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
12 |
13 |
14 |
18 |
19 |
23 |
24 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/alert_choose_photo.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
22 |
23 |
24 |
28 |
29 |
34 |
35 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_brush_width.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
14 |
15 |
21 |
22 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_choose_emoji.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
20 |
21 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
10 |
13 |
14 |
15 |
18 |
19 |
24 |
25 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/include_title.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
14 |
15 |
16 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_cookie.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
17 |
18 |
25 |
26 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_for_custom_spinner.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_forum.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
17 |
24 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_pic_emoji.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_setting_forum.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
17 |
18 |
19 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_tag.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_word_emoji.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/load_state_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
22 |
23 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_article_detail.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_collection.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_cookie.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_drawer.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_history.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_home.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_img.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_new_thread.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_web.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/icon_drawer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-anydpi-v26/icon_drawer.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/icon_emoji.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-anydpi-v26/icon_emoji.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/icon_pic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-anydpi-v26/icon_pic.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/icon_send.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-anydpi-v26/icon_send.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_send.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/ic_send.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/icon_show.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/icon_show.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_1.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_10.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_100.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_101.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_101.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_102.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_102.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_103.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_103.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_104.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_104.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_105.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_105.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_106.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_106.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_11.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_12.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_13.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_14.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_15.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_16.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_17.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_18.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_18.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_19.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_2.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_20.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_21.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_21.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_22.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_22.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_23.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_23.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_24.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_25.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_25.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_26.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_26.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_27.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_27.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_28.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_28.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_29.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_3.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_30.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_30.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_31.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_31.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_32.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_33.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_33.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_34.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_34.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_35.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_35.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_36.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_37.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_37.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_38.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_39.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_39.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_4.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_40.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_41.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_41.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_42.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_43.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_43.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_44.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_44.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_45.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_45.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_46.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_46.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_47.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_47.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_48.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_49.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_49.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_5.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_50.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_51.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_51.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_52.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_52.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_53.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_53.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_54.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_54.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_55.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_55.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_56.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_56.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_57.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_58.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_58.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_59.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_59.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_6.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_60.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_61.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_61.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_62.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_62.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_63.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_63.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_64.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_65.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_65.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_66.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_66.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_67.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_67.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_68.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_68.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_69.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_69.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_7.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_70.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_71.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_71.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_72.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_73.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_73.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_74.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_74.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_75.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_75.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_76.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_77.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_77.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_78.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_78.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_79.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_79.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_8.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_80.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_80.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_81.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_81.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_82.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_82.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_83.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_83.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_84.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_84.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_85.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_85.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_86.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_86.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_87.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_87.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_88.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_88.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_89.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_89.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_9.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_90.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_90.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_91.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_91.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_92.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_92.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_93.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_93.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_94.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_94.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_95.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_95.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_96.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_97.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_97.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_98.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_98.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/lwn_99.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-mdpi/lwn_99.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-night-xxxhdpi/ic_action.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-night-xxxhdpi/ic_action.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-night-xxxhdpi/ic_github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-night-xxxhdpi/ic_github.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_cleaner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-xhdpi/icon_cleaner.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_cleaner_fill.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-xhdpi/icon_cleaner_fill.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_clear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-xhdpi/icon_clear.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_draw_color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-xhdpi/icon_draw_color.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_draw_menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-xhdpi/icon_draw_menu.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_draw_width.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-xhdpi/icon_draw_width.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/app_widget_pic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-xxxhdpi/app_widget_pic.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/bg_cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-xxxhdpi/bg_cover.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_ac.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-xxxhdpi/ic_ac.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_action.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-xxxhdpi/ic_action.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_cookie.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-xxxhdpi/ic_cookie.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_donate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-xxxhdpi/ic_donate.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-xxxhdpi/ic_download.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_drawer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-xxxhdpi/ic_drawer.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_emoji.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-xxxhdpi/ic_emoji.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_full_screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-xxxhdpi/ic_full_screen.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_full_screen_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-xxxhdpi/ic_full_screen_selected.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-xxxhdpi/ic_github.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-xxxhdpi/ic_logo.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_pic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/app/src/main/res/mipmap-xxxhdpi/ic_pic.png
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimen.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 2dp
4 | 0.5dp
5 | 20dp
6 | 40dp
7 | 50dp
8 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/app_widgets_thread.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/provider_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/shortcuts.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
13 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/test/java/com/yollpoll/nmb/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/base/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/base/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'kotlin-android'
4 | id 'kotlin-kapt'
5 | id 'dagger.hilt.android.plugin'//hilt support
6 | }
7 | apply from: "${rootProject.projectDir}/build-framework.gradle"
8 |
9 | android {
10 | compileSdkVersion androidConfig.compileSdkVersion
11 | buildToolsVersion androidConfig.buildToolsVersion
12 |
13 | defaultConfig {
14 | minSdkVersion androidConfig.minSdkVersion
15 | targetSdkVersion androidConfig.targetSdkVersion
16 | versionCode androidConfig.versionCode
17 | versionName androidConfig.versionName
18 |
19 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
20 | consumerProguardFiles "consumer-rules.pro"
21 | }
22 |
23 | buildTypes {
24 | release {
25 | minifyEnabled false
26 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
27 | }
28 | }
29 | compileOptions {
30 | sourceCompatibility JavaVersion.VERSION_1_8
31 | targetCompatibility JavaVersion.VERSION_1_8
32 | }
33 | kotlinOptions {
34 | jvmTarget = '1.8'
35 | }
36 | android.buildFeatures.dataBinding = true
37 | }
38 |
39 | dependencies {
40 |
41 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
42 | implementation 'androidx.core:core-ktx:1.3.1'
43 | implementation 'androidx.appcompat:appcompat:1.2.0'
44 | implementation 'com.google.android.material:material:1.6.1'
45 | testImplementation 'junit:junit:4.+'
46 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
47 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
48 |
49 |
50 | }
--------------------------------------------------------------------------------
/base/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/base/consumer-rules.pro
--------------------------------------------------------------------------------
/base/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/base/src/androidTest/java/com/yollpoll/base/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.base
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.yollpoll.base.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/base/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/base/src/main/java/com/yollpoll/base/AnnouncementDialog.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.base
2 |
3 | import android.app.AlertDialog
4 | import android.app.Dialog
5 | import android.content.Context
6 | import android.text.Html
7 | import androidx.databinding.ViewDataBinding
8 | import androidx.viewbinding.ViewBinding
9 | import com.yollpoll.base.databinding.DialogCommonBinding
10 | import com.yollpoll.framework.widgets.BaseDialog
11 | import com.yollpoll.utils.TransFormContent
12 |
13 | class AnnouncementDialog(
14 | val content: String?,
15 | val context: Context,
16 | private val onUrlClick: ((String) -> Unit)? = null
17 | ) :
18 | NMBDialog(context) {
19 | override fun getLayoutId() = R.layout.dialog_common
20 |
21 | override fun createDialog(context: Context): AlertDialog {
22 | val builder = AlertDialog.Builder(context)
23 | return builder.create()
24 | }
25 |
26 | override fun onInit(dialog: AlertDialog, binding: DialogCommonBinding) {
27 | //文本修改为自定义编辑的模式
28 | if (content?.isNotEmpty() == true) {
29 | TransFormContent.trans(
30 | Html.fromHtml(content),
31 | binding.tvDialog,
32 | ) { url ->
33 | onUrlClick?.invoke(url)
34 | }
35 | }
36 | }
37 |
38 | override fun onDialogDismiss(dialog: AlertDialog) {
39 | }
40 |
41 | override fun onDialogShow(dialog: AlertDialog) {
42 | }
43 |
44 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/yollpoll/base/BaseDialogFragment.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.base
2 |
3 | import android.annotation.SuppressLint
4 | import android.view.View
5 | import android.view.WindowManager
6 | import androidx.fragment.app.DialogFragment
7 | import com.yollpoll.framework.extensions.dp2px
8 |
9 | /**
10 | * Created by 鹏祺 on 2017/7/3.
11 | */
12 | @SuppressLint("ValidFragment")
13 | open class BaseDialogFragment : DialogFragment(), View.OnClickListener {
14 | override fun onStart() {
15 | super.onStart()
16 | val window = dialog!!.window
17 | val layoutParams = window!!.attributes
18 | layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT
19 | layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT
20 | layoutParams.horizontalMargin = requireContext().dp2px(50f)
21 | window.attributes = layoutParams
22 | }
23 |
24 | override fun onClick(v: View) {}
25 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/yollpoll/base/CommonDialog.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.base
2 |
3 | import android.app.ActionBar
4 | import android.content.Context
5 | import android.view.WindowManager
6 | import androidx.appcompat.app.AlertDialog
7 | import com.yollpoll.base.databinding.DialogLayoutBinding
8 | import com.yollpoll.framework.extensions.dp2px
9 |
10 | /**
11 | * Created by spq on 2022/11/11
12 | */
13 | class CommonDialog(
14 | val title: String,
15 | val content: String,
16 | val mContext: Context,
17 | val onCancel: (() -> Unit)? = null,
18 | val onOk: (() -> Unit)? = null
19 | ) : NMBDialog(mContext) {
20 | override fun getLayoutId() = R.layout.dialog_layout
21 |
22 | override fun createDialog(context: Context): AlertDialog {
23 | return AlertDialog.Builder(context).create()
24 | }
25 |
26 | override fun onInit(dialog: AlertDialog?, binding: DialogLayoutBinding?) {
27 | super.onInit(dialog, binding)
28 | binding?.let {
29 | it.dialog = this
30 | it.executePendingBindings()
31 | }
32 | }
33 |
34 | override fun onDialogShow(dialog: AlertDialog) {
35 | super.onDialogShow(dialog)
36 | val lp: WindowManager.LayoutParams = WindowManager.LayoutParams()
37 |
38 | lp.copyFrom(dialog.window?.attributes)
39 |
40 | lp.width = mContext.dp2px(320F).toInt()
41 |
42 | lp.height = mContext.dp2px(200F).toInt()
43 |
44 | dialog.window?.attributes = lp
45 | }
46 |
47 | fun onOk() {
48 | onOk?.invoke()
49 | this.dismiss()
50 | }
51 |
52 | fun onCancel() {
53 | onCancel?.invoke()
54 | this.dismiss()
55 | }
56 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/yollpoll/base/Constant.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb
2 |
3 | const val TAG = "nmb"
4 | const val KEY_FORUM_LIST = "forum_list"
5 | const val USER_AGENT = "NMBClient-yollpoll-android"
6 | const val APP_ID = "yollpoll"
7 | const val KEY_CUR_COOKIE = "current_cookie"
8 | const val KEY_SHOW_ANNOUNCEMENT = "show_announcement"
9 | const val KEY_OPEN_CRASH_HANDLER = "open_crash_handler"
10 | const val KEY_COLLECTION_ID = "collection_id"
11 | const val KEY_NO_COOKIE = "no_cookie"
12 | const val KEY_NO_IMG = "no_img"
13 | const val KEY_BIG_IMG = "big_img"
14 | const val KEY_COOKIE_COLOR = "cookie_color"
15 | const val KEY_FOCUS = "key_focus"
16 |
17 | //eventbus msg
18 | const val ACTION_TAG_NAME = "action_tag_name"
19 | const val ACTION_TAG_ID = "action_tag_id"
20 | const val ACTION_SELECT_THEME = "action_select_theme"
21 | const val ACTION_NO_IMG = "action_no_img"
22 | const val ACTION_NO_COOKIE = "action_no_cookie"
23 | const val ACTION_BIG_IMG = "action_big_img"
24 | const val ACTION_REFRESH_FORUM = "refresh_forum"
25 | const val ACTION_UPDATE_THREAD_DETAIL = "update_thread_detail"
26 | const val ACTION_UPDATE_THREAD_DETAIL_CANCEL = "update_thread_detail_cancel"
27 |
28 | const val AUTHOR = "yollpoll"
29 | const val GIT = "https://github.com/yollpoll/nmb"
30 | const val EMAIL = "iamspq@gmail.com"
31 | const val FIR = "http://d.firim.pro/newnmb"//fir仓库
32 | const val OFFICIAL_WEB="https://www.nmbxd1.com/Member/User/Index/login.html"//官网
33 |
34 |
35 |
--------------------------------------------------------------------------------
/base/src/main/java/com/yollpoll/base/Extension.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.base
2 |
3 | import android.content.Context
4 | import android.util.TypedValue
5 | import com.yollpoll.arch.log.LogUtils
6 |
7 | fun String.logI() {
8 | LogUtils.i(this)
9 | }
10 |
11 | fun String.logE() {
12 | LogUtils.e(this)
13 | }
14 |
15 | fun String.logD() {
16 | LogUtils.d(this)
17 | }
18 |
19 | fun Context.getAttrColor(id: Int): Int {
20 | val typedValue = TypedValue()
21 | theme.resolveAttribute(id, typedValue, true)
22 | return typedValue.data
23 | }
24 |
--------------------------------------------------------------------------------
/base/src/main/java/com/yollpoll/base/NMBApplication.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.base
2 |
3 | import com.yollpoll.arch.log.LogUtils
4 | import com.yollpoll.framework.extensions.getString
5 | import com.yollpoll.framework.extensions.putString
6 | import com.yollpoll.framework.fast.FastApplication
7 | import com.yollpoll.skin.SkinTheme
8 | import com.yollpoll.skin.skinTheme
9 | import dagger.hilt.android.HiltAndroidApp
10 | import kotlinx.coroutines.GlobalScope
11 | import kotlinx.coroutines.launch
12 |
13 | /**
14 | * Created by spq on 2022/6/22
15 | */
16 | open class NMBApplication : FastApplication() {
17 | companion object {
18 | lateinit var INSTANCE:NMBApplication
19 | }
20 |
21 | override fun onCreate() {
22 | super.onCreate()
23 | INSTANCE=this
24 | initTheme()
25 | LogUtils.init(this, "NMB", BuildConfig.DEBUG)
26 | }
27 |
28 | var appSkinTheme: SkinTheme = SkinTheme.NULL
29 | set(value) {
30 | field = value
31 | skinTheme = value
32 | GlobalScope.launch {
33 | putString("theme", value.name)
34 | }
35 | }
36 |
37 | private fun initTheme() {
38 | GlobalScope.launch {
39 | appSkinTheme = SkinTheme.valueOf(getString("theme", SkinTheme.NULL.name))
40 | skinTheme = appSkinTheme
41 | }
42 | }
43 |
44 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/yollpoll/extensions/context.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.extensions
2 |
3 | import android.content.Context
4 | import android.content.res.Configuration
5 | import android.net.ConnectivityManager
6 | import android.net.NetworkInfo
7 |
8 | /**
9 | * Created by spq on 2022/11/18
10 | */
11 | //是否开启黑暗模式
12 | fun Context.isDarkMod(): Boolean {
13 | val curMod = this.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
14 | return curMod == Configuration.UI_MODE_NIGHT_YES
15 | }
16 |
17 | fun Context.isNetConnected(): Boolean {
18 | val manager = this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
19 | val info = manager.allNetworkInfo
20 | info.forEach {
21 | if (it.state == NetworkInfo.State.CONNECTED) {
22 | return true
23 | }
24 | }
25 | return false
26 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/yollpoll/floweventbus/BusInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.floweventbus
2 |
3 | import java.util.concurrent.Flow
4 |
5 | /**
6 | * Created by spq on 2022/1/18
7 | */
8 | interface BusInterceptor {
9 | suspend fun intercept(chain: Chain): Flow
10 |
11 | interface Chain {
12 | suspend fun proceed(): Flow
13 | }
14 | }
15 |
16 | class RealBusChain(private val interceptors: List, private val index: Int) :
17 | BusInterceptor.Chain {
18 | override suspend fun proceed(): Flow {
19 | if (index >= interceptors.size) {
20 | throw Exception("Bus拦截器数量错误: size${interceptors.size} index:$index")
21 | }
22 | val nextChain =
23 | RealBusChain(interceptors, index + 1)
24 | val interceptor = interceptors[index]
25 | return interceptor.intercept(nextChain)
26 | }
27 |
28 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/yollpoll/skin/SkinConfig.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.skin
2 |
3 | /**
4 | * Created by spq on 2022/11/15
5 | */
6 | const val NAMESPACE = "http://schemas.android.com/apk/res-auto"
7 | const val SKIN_ENABLE = "skin_enable"
8 | const val SKIN_TAG = "skin_tag"
9 |
10 | //skin tag
11 | const val ITEM_LINE = "item_line"
12 | const val ITEM = "item"
13 | const val SETTING_ITEM = "setting_item"//各种设置类型的item
14 | const val DIALOG_BG = "dialog_bg"
--------------------------------------------------------------------------------
/base/src/main/java/com/yollpoll/skin/SkinHandler.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.skin
2 |
3 | import android.animation.AnimatorInflater
4 | import android.animation.StateListAnimator
5 | import android.view.View
6 | import com.google.gson.annotations.Until
7 | import com.yollpoll.base.R
8 | import com.yollpoll.base.logI
9 | import com.yollpoll.framework.extensions.dp2px
10 | import com.yollpoll.utils.setViewMargin
11 |
12 | /**
13 | * Created by spq on 2022/11/16
14 | */
15 | val MaterialItemLine = Pair(ITEM_LINE) { parent, name, view, attrs ->
16 | view.visibility = View.GONE
17 | view
18 | }
19 | val MaterialItem = Pair(ITEM) { parent, name, view, attrs ->
20 | "view name: $name".logI()
21 | val context = view.context
22 | val bg = view.context.resources.getDrawable(R.drawable.shape_material_item, null)
23 | view.background = bg
24 | val animator: StateListAnimator =
25 | AnimatorInflater.loadStateListAnimator(view.context, R.animator.material_item_animator)
26 | view.stateListAnimator = animator
27 | view
28 | }
29 | val MaterialSettingItem = Pair(SETTING_ITEM) { parent, name, view, attrs ->
30 | "view name: $name".logI()
31 | val context = view.context
32 | val bg = view.context.resources.getDrawable(R.drawable.shape_material_item, null)
33 | view.background = bg
34 | val animator: StateListAnimator =
35 | AnimatorInflater.loadStateListAnimator(view.context, R.animator.material_item_animator)
36 | view.stateListAnimator = animator
37 | view.setPadding(
38 | context.dp2px(10f).toInt(),
39 | context.dp2px(5f).toInt(),
40 | context.dp2px(10f).toInt(),
41 | context.dp2px(5f).toInt()
42 | )
43 | view
44 | }
45 | val MaterialDialogBg = Pair(DIALOG_BG) { parent, name, view, attrs ->
46 | view
47 | }
48 |
--------------------------------------------------------------------------------
/base/src/main/java/com/yollpoll/utils/BitmapUtils.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.utils
2 |
3 | import android.graphics.*
4 |
5 | /**
6 | * 裁剪完以后会回收旧bitmap
7 | */
8 | fun Bitmap.centerCrop(width: Int, height: Int): Bitmap {
9 | val desRate: Float = width.toFloat() / height
10 | val srcRate: Float = this.width.toFloat() / this.height
11 | var newWidth = this.width
12 | var newHeight = this.height
13 | var dx = 0
14 | var dy = 0
15 | if (desRate == srcRate) {
16 | return this
17 | } else if (srcRate > desRate) {
18 | newWidth = (this.height * desRate).toInt()
19 | dx = (this.width - newWidth) / 2
20 | } else {
21 | newHeight = (this.width / desRate).toInt()
22 | dy = (this.height - newHeight) / 2
23 | }
24 | val res = Bitmap.createBitmap(this, dx, dy, newWidth, newHeight)
25 | this.recycle()
26 | return res
27 | }
28 |
29 | //设置圆角
30 | fun Bitmap.roundCorners(radius: Float): Bitmap {
31 | val res = Bitmap.createBitmap(this.width, this.height, Bitmap.Config.ARGB_8888)
32 | val canvas = Canvas(res)
33 | val paint = Paint()
34 | paint.isAntiAlias = true
35 | paint.shader = BitmapShader(this, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
36 | canvas.drawRoundRect(0f, 0f, this.width.toFloat(), this.height.toFloat(), radius, radius, paint)
37 | this.recycle()
38 | return res
39 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/yollpoll/utils/ImageDownloader.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.utils
2 |
3 | import android.content.Context
4 | import android.graphics.Bitmap
5 | import android.os.Handler
6 | import android.os.Message
7 | import com.bumptech.glide.Glide
8 | import com.bumptech.glide.request.target.Target
9 | import java.io.File
10 | import java.lang.Error
11 | import java.lang.reflect.Field
12 |
13 |
14 | /**
15 | * Created by 鹏祺 on 2017/5/18.
16 | */
17 | class ImageDownloader {
18 | /**
19 | * @param path 路径要注意权限
20 | */
21 | suspend fun download(
22 | imageName: String, path: String,
23 | url: String,
24 | context: Context,
25 | ): DownloadImgRes {
26 | var fileName: String? = null
27 | var bitmap: Bitmap? = null
28 | var file: File? = null
29 | bitmap = Glide.with(context)
30 | .asBitmap()
31 | .load(url)
32 | .submit(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
33 | .get()
34 | if (bitmap != null) {
35 | //保存图片,文件名跟随图片名
36 | fileName = saveBitmapToSd(bitmap, imageName, path)
37 | file = File(fileName)
38 | }
39 | return DownloadImgRes(bitmap, file)
40 | }
41 | }
42 |
43 | data class DownloadImgRes(val bitmap: Bitmap?, val file: File?)
--------------------------------------------------------------------------------
/base/src/main/java/com/yollpoll/utils/MyClickableSpan.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.utils
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.graphics.Color
6 | import android.net.Uri
7 | import android.text.TextPaint
8 | import android.text.style.BackgroundColorSpan
9 | import android.text.style.ClickableSpan
10 | import android.view.View
11 | import com.yollpoll.base.R
12 | import com.yollpoll.base.logE
13 | import com.yollpoll.framework.extensions.shortToast
14 |
15 | /**
16 | * Created by 鹏祺 on 2018/4/27.
17 | */
18 | class MyClickableSpan(
19 | private val url: String,
20 | private val onClickListener: ((String) -> Unit)? = null
21 | ) : ClickableSpan() {
22 | override fun onClick(widget: View) {
23 | onClickListener?.invoke(url)
24 | }
25 |
26 | override fun updateDrawState(ds: TextPaint) {
27 | super.updateDrawState(ds)
28 | ds.isUnderlineText = true
29 | ds.color = Color.parseColor("#7cb342")
30 | }
31 | }
32 |
33 | class MyHideSpan(context:Context):BackgroundColorSpan(context.resources.getColor(R.color.color_hint)){
34 |
35 | }
--------------------------------------------------------------------------------
/base/src/main/res/animator/material_item_animator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
10 |
15 |
20 |
21 |
22 |
23 | -
24 |
25 |
30 |
35 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/base/src/main/res/drawable-night/shape_material_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/base/src/main/res/drawable/shape_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/base/src/main/res/drawable/shape_material_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/base/src/main/res/layout/dialog_common.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
16 |
17 |
21 |
22 |
28 |
29 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/base/src/main/res/mipmap/bg_cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/base/src/main/res/mipmap/bg_cover.png
--------------------------------------------------------------------------------
/base/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/base/src/main/res/values/dimen.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 60dp
4 | 12sp
5 |
--------------------------------------------------------------------------------
/base/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | nmb
3 | 确定
4 | 取消
5 |
--------------------------------------------------------------------------------
/base/src/test/java/com/yollpoll/base/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.base
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | apply from: "config.gradle"
3 | buildscript {
4 | ext.kotlin_version = "1.5.0"
5 | repositories {
6 | google()
7 | mavenCentral()
8 | maven { url "https://www.jitpack.io" }
9 | }
10 | dependencies {
11 | classpath "com.android.tools.build:gradle:4.2.1"
12 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10"
13 | classpath "com.google.dagger:hilt-android-gradle-plugin:2.37"
14 | // NOTE: Do not place your application dependencies here; they belong
15 | // in the individual module build.gradle files
16 | }
17 | }
18 |
19 | allprojects {
20 | repositories {
21 | google()
22 | mavenCentral()
23 | maven { url "https://www.jitpack.io" }
24 | // jcenter() // Warning: this repository is going to shut down soon
25 | }
26 | }
27 |
28 | task clean(type: Delete) {
29 | delete rootProject.buildDir
30 | }
31 | configurations.all {
32 | resolutionStrategy {
33 | // force
34 | }
35 | }
--------------------------------------------------------------------------------
/business/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/business/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'kotlin-android'
4 | }
5 | //apply from: "${rootProject.projectDir}/build-framework.gradle"
6 | android {
7 | compileSdkVersion 33
8 | buildToolsVersion "31.0.0"
9 |
10 | defaultConfig {
11 | minSdkVersion 21
12 | targetSdkVersion 33
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | consumerProguardFiles "consumer-rules.pro"
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 | compileOptions {
27 | sourceCompatibility JavaVersion.VERSION_1_8
28 | targetCompatibility JavaVersion.VERSION_1_8
29 | }
30 | kotlinOptions {
31 | jvmTarget = '1.8'
32 | }
33 | android.buildFeatures.dataBinding = true
34 | }
35 |
36 | dependencies {
37 |
38 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
39 | implementation 'androidx.core:core-ktx:1.8.0'
40 | implementation 'androidx.appcompat:appcompat:1.4.2'
41 | implementation 'com.google.android.material:material:1.6.1'
42 | testImplementation 'junit:junit:4.+'
43 | androidTestImplementation 'androidx.test.ext:junit:1.1.3'
44 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
45 | implementation project(path: ':base')
46 | implementation("com.squareup.okhttp3:okhttp:3.14.9")
47 | }
--------------------------------------------------------------------------------
/business/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/business/consumer-rules.pro
--------------------------------------------------------------------------------
/business/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/business/src/androidTest/java/com/yollpoll/business/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.business
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.yollpoll.business.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/business/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/business/src/main/java/com/yollpoll/business/TestActivity.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.business
2 |
3 | import android.os.Bundle
4 | import android.widget.TextView
5 | import androidx.appcompat.app.AppCompatActivity
6 | import okhttp3.OkHttpClient
7 |
8 | class TestActivity:AppCompatActivity() {
9 | override fun onCreate(savedInstanceState: Bundle?) {
10 | super.onCreate(savedInstanceState)
11 | val tv=TextView(this)
12 | tv.text="hello world"
13 | setContentView(tv)
14 |
15 | val builder= OkHttpClient.Builder()
16 | builder.build()
17 | }
18 | }
--------------------------------------------------------------------------------
/business/src/main/res/layout/activity_home.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/business/src/main/res/values/dimen.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/business/src/test/java/com/yollpoll/business/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.business
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Jun 22 10:08:45 CST 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/ilog/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/ilog/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'kotlin-android'
4 | }
5 |
6 | android {
7 | compileSdkVersion 33
8 | buildToolsVersion "31.0.0"
9 |
10 | defaultConfig {
11 | minSdkVersion 21
12 | targetSdkVersion 33
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | consumerProguardFiles "consumer-rules.pro"
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 | compileOptions {
27 | sourceCompatibility JavaVersion.VERSION_1_8
28 | targetCompatibility JavaVersion.VERSION_1_8
29 | }
30 | kotlinOptions {
31 | jvmTarget = '1.8'
32 | }
33 | }
34 |
35 | dependencies {
36 |
37 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
38 | implementation 'androidx.appcompat:appcompat:1.2.0'
39 | implementation 'com.google.android.material:material:1.2.1'
40 | testImplementation 'junit:junit:4.+'
41 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
42 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
43 | }
--------------------------------------------------------------------------------
/ilog/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/ilog/consumer-rules.pro
--------------------------------------------------------------------------------
/ilog/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/ilog/src/androidTest/java/com/yollpoll/ilog/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.ilog
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.yollpoll.ilog.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/ilog/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/ilog/src/main/java/com/yollpoll/ilog/Ilog.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.ilog
2 |
3 | /**
4 | * Created by spq on 2022/1/14
5 | */
6 | interface Ilog {
7 | fun saveLog(fileName: String, content: String)
8 | }
--------------------------------------------------------------------------------
/ilog/src/test/java/com/yollpoll/ilog/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.ilog
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/iqr/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/iqr/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'kotlin-android'
4 | id 'kotlin-kapt'
5 | id 'dagger.hilt.android.plugin'//hilt support
6 | }
7 | apply from: "${rootProject.projectDir}/build-framework.gradle"
8 | android {
9 | namespace 'com.yollpoll.iqr'
10 | compileSdkVersion 32
11 |
12 | defaultConfig {
13 | minSdkVersion 21
14 | targetSdkVersion 32
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | consumerProguardFiles "consumer-rules.pro"
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 | compileOptions {
27 | sourceCompatibility JavaVersion.VERSION_1_8
28 | targetCompatibility JavaVersion.VERSION_1_8
29 | }
30 | kotlinOptions {
31 | jvmTarget = '1.8'
32 | }
33 | }
34 |
35 | dependencies {
36 |
37 | implementation 'androidx.core:core-ktx:1.7.0'
38 | implementation 'androidx.appcompat:appcompat:1.4.1'
39 | implementation 'com.google.android.material:material:1.6.0'
40 | testImplementation 'junit:junit:4.13.2'
41 | androidTestImplementation 'androidx.test.ext:junit:1.1.4'
42 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
43 | implementation project(path: ':base')
44 | }
--------------------------------------------------------------------------------
/iqr/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/iqr/consumer-rules.pro
--------------------------------------------------------------------------------
/iqr/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/iqr/src/androidTest/java/com/yollpoll/nmb/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.yollpoll.nmb.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/iqr/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/iqr/src/main/java/com/yollpoll/nmb/Iqr.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb
2 |
3 | import android.content.Context
4 | import android.net.Uri
5 | import com.google.mlkit.vision.barcode.Barcode
6 |
7 | interface Iqr {
8 | fun analysisQr(uri: Uri,
9 | context: Context,
10 | onResult: ((List) -> Unit)? = null,
11 | onErr: ((Exception) -> Unit)?,
12 | onComplete: (() -> Unit)?)
13 |
14 | }
--------------------------------------------------------------------------------
/iqr/src/test/java/com/yollpoll/nmb/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.nmb
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/log/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/log/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'kotlin-android'
4 | id 'kotlin-kapt'
5 | id 'dagger.hilt.android.plugin'//hilt support
6 | }
7 | apply from: "${rootProject.projectDir}/build-framework.gradle"
8 | android {
9 | compileSdkVersion 33
10 | buildToolsVersion "31.0.0"
11 |
12 | defaultConfig {
13 | minSdkVersion 21
14 | targetSdkVersion 33
15 | versionCode 1
16 | versionName "1.0"
17 |
18 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
19 | consumerProguardFiles "consumer-rules.pro"
20 | }
21 |
22 | buildTypes {
23 | release {
24 | minifyEnabled false
25 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
26 | }
27 | }
28 | compileOptions {
29 | sourceCompatibility JavaVersion.VERSION_1_8
30 | targetCompatibility JavaVersion.VERSION_1_8
31 | }
32 | kotlinOptions {
33 | jvmTarget = '1.8'
34 | }
35 | }
36 |
37 | dependencies {
38 |
39 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
40 | implementation project(path: ':ilog')
41 | implementation 'androidx.core:core-ktx:1.3.1'
42 | implementation 'androidx.appcompat:appcompat:1.2.0'
43 | implementation 'com.google.android.material:material:1.2.1'
44 | implementation project(path: ':base')
45 | testImplementation 'junit:junit:4.+'
46 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
47 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
48 |
49 | }
--------------------------------------------------------------------------------
/log/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/log/consumer-rules.pro
--------------------------------------------------------------------------------
/log/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/log/src/androidTest/java/com/yollpoll/log/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.log
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.yollpoll.log.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/log/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/log/src/main/java/com/yollpoll/log/CloseUtils.java:
--------------------------------------------------------------------------------
1 | package com.yollpoll.log;
2 |
3 | import java.io.Closeable;
4 | import java.io.IOException;
5 |
6 | /**
7 | * @Title:关闭相关工具类
8 | * @Author: djk
9 | * @Time: 2017/8/2
10 | * @Version:1.0.0
11 | */
12 | public final class CloseUtils {
13 |
14 | private CloseUtils() {
15 | throw new UnsupportedOperationException("u can't instantiate me...");
16 | }
17 |
18 | /**
19 | * 关闭IO
20 | *
21 | * @param closeables closeables
22 | */
23 | public static void closeIO(final Closeable... closeables) {
24 | if (closeables == null) return;
25 | for (Closeable closeable : closeables) {
26 | if (closeable != null) {
27 | try {
28 | closeable.close();
29 | } catch (IOException e) {
30 | e.printStackTrace();
31 | }
32 | }
33 | }
34 | }
35 |
36 | /**
37 | * 安静关闭IO
38 | *
39 | * @param closeables closeables
40 | */
41 | public static void closeIOQuietly(final Closeable... closeables) {
42 | if (closeables == null) return;
43 | for (Closeable closeable : closeables) {
44 | if (closeable != null) {
45 | try {
46 | closeable.close();
47 | } catch (IOException ignored) {
48 | }
49 | }
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/log/src/main/java/com/yollpoll/log/ILogImpl.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.log
2 |
3 | import android.content.Context
4 | import com.yollpoll.ilog.Ilog
5 | import dagger.hilt.android.qualifiers.ApplicationContext
6 | import javax.inject.Inject
7 |
8 | /**
9 | * Created by spq on 2022/1/14
10 | */
11 | class ILogImpl @Inject constructor(@ApplicationContext val context: Context) : Ilog {
12 | override fun saveLog(fileName: String, content: String) {
13 | LogWorkerManager.enqueue(fileName, content, context)
14 | }
15 | }
--------------------------------------------------------------------------------
/log/src/main/java/com/yollpoll/log/LogReceiver.java:
--------------------------------------------------------------------------------
1 | package com.yollpoll.log;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.util.Log;
7 |
8 | /**
9 | * Created by spq on 2021/7/5
10 | */
11 | public class LogReceiver extends BroadcastReceiver {
12 | private static final String TAG = "LogReceiver";
13 |
14 | @Override
15 | public void onReceive(Context context, Intent intent) {
16 | Log.d(TAG, "onReceive: 收到广播");
17 | LogService.startLogService(intent.getStringExtra("name"),
18 | intent.getStringExtra("content"),
19 | context);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/log/src/main/java/com/yollpoll/log/LogService.java:
--------------------------------------------------------------------------------
1 | package com.yollpoll.log;
2 |
3 | import android.app.Activity;
4 | import android.app.IntentService;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.util.Log;
8 |
9 | /**
10 | * Created by spq on 2021/7/5
11 | */
12 | public class LogService extends IntentService {
13 | private static final String TAG = "LogService";
14 |
15 | public static void startLogService(String name, String content, Context context) {
16 | Intent intent = new Intent(context, LogService.class);
17 | intent.putExtra("name", name);
18 | intent.putExtra("content", content);
19 | context.startService(intent);
20 | }
21 |
22 | /**
23 | * Creates an IntentService. Invoked by your subclass's constructor.
24 | *
25 | */
26 | public LogService() {
27 | super("aispeech-log");
28 | }
29 |
30 | @Override
31 | protected void onHandleIntent( Intent intent) {
32 | Log.d(TAG, "onHandleIntent: 开始保存文件");
33 | String name = intent.getStringExtra("name");
34 | String content = intent.getStringExtra("content");
35 | LogTools.saveLog(name, content, this);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/log/src/main/java/com/yollpoll/log/LogTools.java:
--------------------------------------------------------------------------------
1 | package com.yollpoll.log;
2 |
3 | import android.content.Context;
4 |
5 | import java.io.File;
6 | import java.text.SimpleDateFormat;
7 | import java.util.Date;
8 |
9 | /**
10 | * Created by spq on 2021/7/5
11 | */
12 | public class LogTools {
13 | static SimpleDateFormat logSimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
14 |
15 | /**
16 | * 保存log到本地
17 | *
18 | * @param name 文件名
19 | * @param log 日志内容
20 | * @param context context
21 | */
22 | public static synchronized boolean saveLog(String name, String log, Context context) {
23 | File file = FileUtils.createFile(name, FileUtils.DirType.LOG, context);
24 | return MKFileIOUtils.writeFileFromString(file, log, true);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/log/src/main/java/com/yollpoll/log/LogWorker.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.log
2 |
3 | import android.content.Context
4 | import androidx.work.*
5 | import java.text.SimpleDateFormat
6 | import java.util.*
7 |
8 | /**
9 | * Created by spq on 2022/1/14
10 | */
11 |
12 | const val DIVIDER_LINE = "****************************************************************"
13 | const val DATA_FORMAT = "yyyy-MM-dd hh:mm:ss"
14 |
15 | class LogWorker(val context: Context, workerParam: WorkerParameters) :
16 | Worker(context, workerParam) {
17 | override fun doWork(): Result {
18 | val name = inputData.getString("name")
19 | var content = inputData.getString("content")
20 |
21 | val sdf = SimpleDateFormat(DATA_FORMAT)
22 | val data = "[${sdf.format(Date())}]\n"
23 | content = data + content + "\n\n$DIVIDER_LINE\n\n"
24 | if (LogTools.saveLog(name, content, context)) {
25 | return Result.success()
26 | } else {
27 | return Result.failure()
28 | }
29 | }
30 |
31 | }
32 |
33 | object LogWorkerManager {
34 | fun enqueue(name: String, content: String, context: Context) {
35 | val saveLogRequest =
36 | OneTimeWorkRequestBuilder().setInputData(
37 | Data.Builder().putString("name", name)
38 | .putString("content", content).build()
39 | )
40 | .build()
41 |
42 | WorkManager.getInstance(context).enqueue(saveLogRequest)
43 | }
44 | }
--------------------------------------------------------------------------------
/log/src/test/java/com/yollpoll/log/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.log
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/qrlib/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/qrlib/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'org.jetbrains.kotlin.android'
4 | id 'kotlin-kapt'
5 | id 'dagger.hilt.android.plugin'//hilt support
6 | }
7 | apply from: "${rootProject.projectDir}/build-framework.gradle"
8 | android {
9 | compileSdkVersion androidConfig.compileSdkVersion
10 | buildToolsVersion androidConfig.buildToolsVersion
11 | defaultConfig {
12 | minSdkVersion 21
13 | targetSdkVersion androidConfig.targetSdkVersion
14 |
15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
16 | consumerProguardFiles "consumer-rules.pro"
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 | compileOptions {
26 | sourceCompatibility JavaVersion.VERSION_1_8
27 | targetCompatibility JavaVersion.VERSION_1_8
28 | }
29 | kotlinOptions {
30 | jvmTarget = '1.8'
31 | }
32 | android.buildFeatures.dataBinding = true
33 | }
34 |
35 | dependencies {
36 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
37 | implementation 'androidx.core:core-ktx:1.8.0'
38 | implementation 'androidx.appcompat:appcompat:1.4.1'
39 | implementation 'com.google.android.material:material:1.6.0'
40 | implementation project(path: ':iqr')
41 | testImplementation 'junit:junit:4.+'
42 | androidTestImplementation 'androidx.test.ext:junit:1.1.3'
43 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
44 | implementation project(path: ':base')
45 | }
--------------------------------------------------------------------------------
/qrlib/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/qrlib/consumer-rules.pro
--------------------------------------------------------------------------------
/qrlib/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/qrlib/src/androidTest/java/com/yollpoll/qrlib/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.qrlib
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.yollpoll.qrlib.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/qrlib/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/qrlib/src/main/java/com/yollpoll/qrlib/QrCodeAnalyzer.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.qrlib
2 |
3 | import android.annotation.SuppressLint
4 | import android.util.Log
5 | import androidx.camera.core.ImageAnalysis
6 | import androidx.camera.core.ImageProxy
7 | import com.google.mlkit.vision.barcode.Barcode
8 | import com.google.mlkit.vision.barcode.BarcodeScannerOptions
9 | import com.google.mlkit.vision.barcode.BarcodeScanning
10 | import com.google.mlkit.vision.common.InputImage
11 |
12 | class QRCodeAnalyser(private val listener: (List, Int, Int) -> Unit) :
13 | ImageAnalysis.Analyzer {
14 | //配置当前扫码格式
15 | private val options = BarcodeScannerOptions.Builder()
16 | .setBarcodeFormats(
17 | Barcode.FORMAT_QR_CODE,
18 | Barcode.FORMAT_AZTEC
19 | ).build()
20 |
21 | //获取解析器
22 | private val detector = BarcodeScanning.getClient(options)
23 |
24 | @SuppressLint("UnsafeExperimentalUsageError", "UnsafeOptInUsageError")
25 | override fun analyze(imageProxy: ImageProxy) {
26 | val mediaImage = imageProxy.image ?: kotlin.run {
27 | imageProxy.close()
28 | return
29 | }
30 | val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
31 | detector.process(image)
32 | .addOnSuccessListener { barCodes ->
33 | Log.e("ztzt", "barCodes: ${barCodes.size}")
34 | if (barCodes.size > 0) {
35 | listener.invoke(barCodes, imageProxy.width, imageProxy.height)
36 | //接收到结果后,就关闭解析
37 | detector.close()
38 | }
39 | }
40 | .addOnFailureListener { Log.e("ztzt", "Error: ${it.message}") }
41 | .addOnCompleteListener { imageProxy.close() }
42 | }
43 | }
--------------------------------------------------------------------------------
/qrlib/src/main/java/com/yollpoll/qrlib/QrUtils.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.qrlib
2 |
3 | import android.content.Context
4 | import android.media.Image
5 | import android.net.Uri
6 | import android.util.Log
7 | import com.google.mlkit.vision.barcode.Barcode
8 | import com.google.mlkit.vision.barcode.BarcodeScannerOptions
9 | import com.google.mlkit.vision.barcode.BarcodeScanning
10 | import com.google.mlkit.vision.common.InputImage
11 | import com.yollpoll.nmb.Iqr
12 | import kotlinx.coroutines.Deferred
13 | import java.lang.Exception
14 |
15 | /**
16 | * Created by spq on 2022/11/8
17 | */
18 | class QrUtils :Iqr{
19 | override fun analysisQr(
20 | uri: Uri,
21 | context: Context,
22 | onResult: ((List) -> Unit)?,
23 | onErr: ((Exception) -> Unit)?,
24 | onComplete: (() -> Unit)?
25 | ) {
26 | //配置当前扫码格式
27 | val options = BarcodeScannerOptions.Builder()
28 | .setBarcodeFormats(
29 | Barcode.FORMAT_QR_CODE,
30 | Barcode.FORMAT_AZTEC
31 | ).build()
32 |
33 | //获取解析器
34 | val detector = BarcodeScanning.getClient(options)
35 | val image = InputImage.fromFilePath(context, uri)
36 | detector.process(image)
37 | .addOnSuccessListener {
38 | onResult?.invoke(it)
39 | }
40 | .addOnFailureListener {
41 | onErr?.invoke(it)
42 | }
43 | .addOnCompleteListener {
44 | onComplete?.invoke()
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/qrlib/src/main/res/drawable/ic_photo.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/qrlib/src/main/res/drawable/icon_focus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/qrlib/src/main/res/drawable/icon_focus.png
--------------------------------------------------------------------------------
/qrlib/src/main/res/drawable/scan_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yollpoll/nmb/c42816ca1cfbfcae7a825f409af76ca3f8eb558c/qrlib/src/main/res/drawable/scan_light.png
--------------------------------------------------------------------------------
/qrlib/src/main/res/layout/activity_qr_code.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
11 |
12 |
16 |
17 |
22 |
31 |
32 |
--------------------------------------------------------------------------------
/qrlib/src/test/java/com/yollpoll/qrlib/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.yollpoll.qrlib
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = "nmb"
2 | include ':app'
3 | include ':base'
4 | include ':log'
5 | include ':ilog'
6 | include ':business'
7 | include ':qrlib'
8 | include ':iqr'
9 |
--------------------------------------------------------------------------------