├── .circleci
└── config.yml
├── .gitignore
├── .idea
├── .gitignore
├── assetWizardSettings.xml
├── codeStyles
│ ├── Project.xml
│ └── codeStyleConfig.xml
├── compiler.xml
├── deploymentTargetDropDown.xml
├── dictionaries
│ └── fdx.xml
├── jarRepositories.xml
├── kotlinc.xml
└── vcs.xml
├── .travis.yml
├── License.txt
├── README-zh.md
├── README.md
├── app
├── build.gradle.kts
├── google-services.json
├── proguard-rules.pro
└── src
│ ├── debug
│ └── res
│ │ └── values
│ │ └── strings.xml
│ ├── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-playstore.png
│ ├── ic_launcher-web.png
│ ├── ic_notification_icon-web.png
│ ├── ic_settings-web.png
│ ├── java
│ │ └── im
│ │ │ └── fdx
│ │ │ └── v2ex
│ │ │ ├── MyApp.kt
│ │ │ ├── MyGlideModule.kt
│ │ │ ├── database
│ │ │ ├── AppDatabase.kt
│ │ │ └── DbHelper.kt
│ │ │ ├── model
│ │ │ ├── Data.kt
│ │ │ ├── NotificationModel.kt
│ │ │ ├── Res.kt
│ │ │ └── VModel.kt
│ │ │ ├── network
│ │ │ ├── Api.kt
│ │ │ ├── GetMoreRepliesWorker.kt
│ │ │ ├── GetMsgWorker.kt
│ │ │ ├── HttpHelper.kt
│ │ │ ├── NetManager.kt
│ │ │ ├── Parser.kt
│ │ │ └── cookie
│ │ │ │ ├── CookiePersistor.kt
│ │ │ │ ├── MyCookieJar.kt
│ │ │ │ └── SharedPrefsPersistor.kt
│ │ │ ├── ui
│ │ │ ├── BaseActivity.kt
│ │ │ ├── BaseFragment.kt
│ │ │ ├── LoginActivity.kt
│ │ │ ├── MyCallback.kt
│ │ │ ├── NotificationActivity.kt
│ │ │ ├── NotificationAdapter.kt
│ │ │ ├── PhotoActivity.kt
│ │ │ ├── SettingsActivity.kt
│ │ │ ├── TabSettingActivity.kt
│ │ │ ├── TestActivity.kt
│ │ │ ├── WebViewActivity.kt
│ │ │ ├── favor
│ │ │ │ ├── FavorActivity.kt
│ │ │ │ ├── FavorViewPagerAdapter.kt
│ │ │ │ └── NodeFavorFragment.kt
│ │ │ ├── main
│ │ │ │ ├── Comment.kt
│ │ │ │ ├── MainActivity.kt
│ │ │ │ ├── MyDiffCallback.kt
│ │ │ │ ├── MyViewPagerAdapter.kt
│ │ │ │ ├── NewTopicActivity.kt
│ │ │ │ ├── SearchActivity.kt
│ │ │ │ ├── Topic.kt
│ │ │ │ ├── TopicDao.kt
│ │ │ │ ├── TopicsFragment.kt
│ │ │ │ ├── TopicsRVAdapter.kt
│ │ │ │ └── model
│ │ │ │ │ └── SearchResult.kt
│ │ │ ├── member
│ │ │ │ ├── DiffReply.kt
│ │ │ │ ├── Member.kt
│ │ │ │ ├── MemberActivity.kt
│ │ │ │ ├── MemberReplyModel.kt
│ │ │ │ ├── ReplyAdapter.kt
│ │ │ │ └── UserReplyFragment.kt
│ │ │ ├── node
│ │ │ │ ├── AllNodesActivity.kt
│ │ │ │ ├── AllNodesAdapter.kt
│ │ │ │ ├── AllNodesAdapterNew.kt
│ │ │ │ ├── Node.kt
│ │ │ │ ├── NodeActivity.kt
│ │ │ │ ├── NodeDao.kt
│ │ │ │ └── SimpleNodesTextAdapter.kt
│ │ │ └── topic
│ │ │ │ ├── BottomReplyList.kt
│ │ │ │ ├── MyReply.kt
│ │ │ │ ├── MyReplyDao.kt
│ │ │ │ ├── Reply.kt
│ │ │ │ ├── TopicActivity.kt
│ │ │ │ ├── TopicAdapter.kt
│ │ │ │ └── TopicFragment.kt
│ │ │ ├── utils
│ │ │ ├── EndlessOnScrollListener.kt
│ │ │ ├── ImageUtil.kt
│ │ │ ├── Keys.kt
│ │ │ ├── SecureUtils.java
│ │ │ ├── TimeUtil.kt
│ │ │ ├── ViewUtil.kt
│ │ │ └── extensions
│ │ │ │ ├── DpExt.kt
│ │ │ │ ├── Hint.kt
│ │ │ │ ├── StringExt.kt
│ │ │ │ └── ViewExt.kt
│ │ │ └── view
│ │ │ ├── BitmapHolder.kt
│ │ │ ├── BottomSheetMenu.kt
│ │ │ ├── CustomChrome.kt
│ │ │ ├── GoodTextView.kt
│ │ │ ├── NaviItem.kt
│ │ │ ├── PageNumberView.kt
│ │ │ ├── Popup.kt
│ │ │ ├── ViewPagerHelper.kt
│ │ │ └── ZoomOutPageTransform.kt
│ ├── logo-alpha.png
│ ├── logo.png
│ └── res
│ │ ├── anim
│ │ ├── hide_toolbar.xml
│ │ ├── node_title_ctl.xml
│ │ ├── rotate_refresh.xml
│ │ └── show_toolbar.xml
│ │ ├── drawable-night
│ │ └── ic_night_mode.xml
│ │ ├── drawable-xxhdpi
│ │ ├── bg_nav_header.png
│ │ ├── ic_shortcut_create.png
│ │ ├── loading_image.png
│ │ └── loading_image_4_3.png
│ │ ├── drawable
│ │ ├── baseline_arrow_drop_down_24.xml
│ │ ├── baseline_close_24.xml
│ │ ├── baseline_manage_search_24.xml
│ │ ├── border.xml
│ │ ├── border_page_num.xml
│ │ ├── divider.xml
│ │ ├── edit_selector.xml
│ │ ├── ic_add_white_24dp.xml
│ │ ├── ic_all_node.xml
│ │ ├── ic_announcement_hint_24dp.xml
│ │ ├── ic_arrow_back_primary_24dp.xml
│ │ ├── ic_baseline_account_circle_24.xml
│ │ ├── ic_baseline_add_circle_outline_24.xml
│ │ ├── ic_baseline_arrow_downward_24.xml
│ │ ├── ic_baseline_remove_circle_outline_24.xml
│ │ ├── ic_baseline_report_24.xml
│ │ ├── ic_bitcoin.xml
│ │ ├── ic_block_primary_24dp.xml
│ │ ├── ic_block_white_24dp.xml
│ │ ├── ic_check_black_24dp.xml
│ │ ├── ic_circle.xml
│ │ ├── ic_comment.xml
│ │ ├── ic_daily_check.xml
│ │ ├── ic_dehaze_black_24dp.xml
│ │ ├── ic_delete.xml
│ │ ├── ic_edit_white_24dp.xml
│ │ ├── ic_favorite_black_24dp.xml
│ │ ├── ic_favorite_blue_24dp.xml
│ │ ├── ic_favorite_border_black_24dp.xml
│ │ ├── ic_favorite_border_white_24dp.xml
│ │ ├── ic_favorite_white_24dp.xml
│ │ ├── ic_github.xml
│ │ ├── ic_image.xml
│ │ ├── ic_location.xml
│ │ ├── ic_message_black_24dp.xml
│ │ ├── ic_night_mode.xml
│ │ ├── ic_notification_with_red_point.xml
│ │ ├── ic_notifications_none_black_24dp.xml
│ │ ├── ic_notifications_primary_24dp.xml
│ │ ├── ic_notifications_white_24dp.xml
│ │ ├── ic_person_outline_black_24dp.xml
│ │ ├── ic_profile.xml
│ │ ├── ic_refresh_white_24dp.xml
│ │ ├── ic_search_primary_24dp.xml
│ │ ├── ic_search_white_48px.xml
│ │ ├── ic_send_black_24dp.xml
│ │ ├── ic_send_hint_24dp.xml
│ │ ├── ic_send_primary_24dp.xml
│ │ ├── ic_send_white_24dp.xml
│ │ ├── ic_settings_24dp.xml
│ │ ├── ic_share_24dp.xml
│ │ ├── ic_share_white_24dp.xml
│ │ ├── ic_thank.xml
│ │ ├── ic_thank_new.xml
│ │ ├── ic_thumbs_up.xml
│ │ ├── ic_twitter.xml
│ │ ├── ic_website.xml
│ │ ├── ic_zoom_out_map_black_24dp.xml
│ │ ├── loading.xml
│ │ ├── logo2x.png
│ │ ├── radius_2dp.xml
│ │ ├── radius_4dp.xml
│ │ ├── radius_8dp.xml
│ │ ├── radius_outline_4dp.xml
│ │ ├── radius_outline_4dp_primary.xml
│ │ ├── rounded_close_24.xml
│ │ ├── spinner.xml
│ │ └── themed_icon.xml
│ │ ├── layout
│ │ ├── activity_all_nodes.xml
│ │ ├── activity_base.xml
│ │ ├── activity_create_topic.xml
│ │ ├── activity_details.xml
│ │ ├── activity_details_content.xml
│ │ ├── activity_follow_activity.xml
│ │ ├── activity_login.xml
│ │ ├── activity_main_content.xml
│ │ ├── activity_main_nav_drawer.xml
│ │ ├── activity_member.xml
│ │ ├── activity_node.xml
│ │ ├── activity_notification.xml
│ │ ├── activity_photo.xml
│ │ ├── activity_search_result.xml
│ │ ├── activity_settings.xml
│ │ ├── activity_tab_setting.xml
│ │ ├── activity_test.xml
│ │ ├── activity_web_view.xml
│ │ ├── app_toolbar.xml
│ │ ├── appbar.xml
│ │ ├── bottom_list_sheet.xml
│ │ ├── dialog_et.xml
│ │ ├── divider.xml
│ │ ├── fragment_tab_article.xml
│ │ ├── item_all_nodes.xml
│ │ ├── item_comments.xml
│ │ ├── item_load_more.xml
│ │ ├── item_node.xml
│ │ ├── item_node_simple.xml
│ │ ├── item_node_with_category.xml
│ │ ├── item_notification.xml
│ │ ├── item_reply_member.xml
│ │ ├── item_reply_view.xml
│ │ ├── item_text_switch.xml
│ │ ├── item_topic_view.xml
│ │ ├── item_topic_with_comments.xml
│ │ ├── iv_refresh.xml
│ │ ├── navi_item.xml
│ │ ├── page_item.xml
│ │ ├── pager_item.xml
│ │ ├── popwindow_bottom.xml
│ │ ├── simple_list_item.xml
│ │ ├── simple_list_item_center.xml
│ │ ├── text_view_spinner.xml
│ │ └── view_page_number.xml
│ │ ├── menu
│ │ ├── menu_activity_nav_drawer.xml
│ │ ├── menu_all_node.xml
│ │ ├── menu_details.xml
│ │ ├── menu_main.xml
│ │ ├── menu_member.xml
│ │ ├── menu_node.xml
│ │ ├── menu_reply.xml
│ │ ├── menu_search.xml
│ │ ├── menu_tab_setting.xml
│ │ └── menu_topic_fragement.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ ├── ic_launcher_round.png
│ │ └── ic_notification_icon.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ ├── ic_launcher_round.png
│ │ └── ic_notification_icon.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ ├── ic_launcher_round.png
│ │ └── ic_notification_icon.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ ├── ic_launcher_round.png
│ │ └── ic_notification_icon.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ ├── ic_launcher_round.png
│ │ └── ic_notification_icon.png
│ │ ├── transition
│ │ ├── change_image_transform.xml
│ │ └── explode.xml
│ │ ├── values-night
│ │ ├── colors.xml
│ │ └── styles.xml
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ ├── values-zh-rCN
│ │ └── strings.xml
│ │ ├── values-zh-rTW
│ │ └── strings.xml
│ │ ├── values
│ │ ├── attrs.xml
│ │ ├── attrs_navi_item.xml
│ │ ├── attrs_page_number_view.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ │ ├── xml-v25
│ │ └── shortcuts.xml
│ │ └── xml
│ │ ├── backup_descriptor.xml
│ │ ├── preference.xml
│ │ ├── preference_login.xml
│ │ ├── provider_paths.xml
│ │ ├── remote_config_defaults.xml
│ │ └── searchable.xml
│ └── testDebug
│ └── java
│ └── im
│ └── fdx
│ └── v2ex
│ ├── network
│ ├── HttpHelperTest.kt
│ └── JsonManagerTest.kt
│ └── utils
│ ├── ContentUtilsTest.kt
│ ├── SecureUtilsTest.kt
│ ├── StringTest.kt
│ ├── TimeUtilTest.kt
│ └── extensions
│ └── StringExtKtTest.kt
├── build.gradle.kts
├── fastlane
├── Appfile
├── Fastfile
├── README.md
└── metadata
│ └── android
│ └── zh-CN
│ ├── changelogs
│ ├── 61.txt
│ ├── 62.txt
│ ├── 66.txt
│ ├── 69.txt
│ └── default.txt
│ ├── full_description.txt
│ ├── images
│ ├── featureGraphic.png
│ ├── icon.png
│ └── phoneScreenshots
│ │ ├── 1_zh-CN.jpeg
│ │ ├── 2_zh-CN.jpeg
│ │ ├── 3_zh-CN.jpeg
│ │ ├── 4_zh-CN.jpeg
│ │ └── 5_zh-CN.jpeg
│ ├── short_description.txt
│ ├── title.txt
│ └── video.txt
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── privacy.md
├── searchablespinnerlibrary
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── toptoche
│ │ └── searchablespinnerlibrary
│ │ └── ApplicationTest.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── toptoche
│ │ └── searchablespinnerlibrary
│ │ ├── SearchableListDialog.java
│ │ └── SearchableSpinner.java
│ └── res
│ ├── layout
│ └── searchable_list_dialog.xml
│ ├── nobleltevzwLMY47XMeditab02192016201518.gif
│ └── values
│ ├── attrs.xml
│ └── strings.xml
└── settings.gradle.kts
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | build:
4 | working_directory: ~/code
5 | docker:
6 | - image: circleci/android:api-30-alpha
7 | # auth:
8 | # username: mydockerhub-user
9 | # password: $DOCKERHUB_PASSWORD # context / project UI env-var reference
10 | environment:
11 | JVM_OPTS: -Xmx3200m
12 | steps:
13 | - checkout
14 | - restore_cache:
15 | key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
16 | # - run:
17 | # name: Chmod permissions #if permission for Gradlew Dependencies fail, use this.
18 | # command: sudo chmod +x ./gradlew
19 | - run:
20 | name: Download Dependencies
21 | command: ./gradlew androidDependencies
22 | - save_cache:
23 | paths:
24 | - ~/.gradle
25 | key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
26 | - run:
27 | name: Run Tests
28 | command: ./gradlew lint test
29 | - store_artifacts: # for display in Artifacts: https://circleci.com/docs/2.0/artifacts/
30 | path: app/build/reports
31 | destination: reports
32 | - store_test_results: # for display in Test Summary: https://circleci.com/docs/2.0/collect-test-data/
33 | path: app/build/test-results
34 | # See https://circleci.com/docs/2.0/deployment-integrations/ for deploy examples
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | /.idea/caches
6 | /app/build
7 | /.idea/misc.xml
8 | /.idea/gradle.xml
9 | /.idea/profile_settings.xml
10 | *.iml
11 | /build
12 | .DS_Store
13 | /captures
14 | /app/app-release.apk
15 | keystore.properties
16 | *.apk
17 | *.aab
18 | output.json
19 | /app/release/output-metadata.json
20 | /fastlane/report.xml
21 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | shelf/
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/deploymentTargetDropDown.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/dictionaries/fdx.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | crashlytic
5 | horz
6 | louzu
7 | objs
8 | persistor
9 | signin
10 | signup
11 | unfavor
12 | unfavorite
13 | vert
14 |
15 |
16 |
--------------------------------------------------------------------------------
/.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/kotlinc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: android
2 | android:
3 | components:
4 | - tools
5 | - build-tools-27.0.3
6 | - platform-tools
7 | - android-27
8 | - extra-android-m2repository
9 | - extra-android-support
10 | - extra-google-m2repository
11 | licenses:
12 | - android-sdk-preview-license-52d11cd2
13 | - android-sdk-license-.+
14 | - google-gdk-license-.+
15 | - ".+"
16 | jdk:
17 | - oraclejdk8
18 | before_install:
19 | - mkdir "$ANDROID_HOME/licenses" || true
20 | - echo -e "\n8933bad161af4178b1185d1a37fbf41ea5269c55\nd56f5187479451eabf01fb78af6dfcb131a6481e" > "$ANDROID_HOME/licenses/android-sdk-license"
21 | - echo -e "\n7c928e048b455a44b323aba54342415d0429c542\n84831b9409646a918e30573bab4c9c91346d8abd" > "$ANDROID_HOME/licenses/android-sdk-preview-license"
22 | before_cache:
23 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
24 | - rm -fr $HOME/.gradle/caches/*/plugin-resolution/
25 | cache:
26 | directories:
27 | - "$HOME/.gradle/caches/"
28 | - "$HOME/.gradle/wrapper/"
29 | script: "./gradlew assembleDebug"
30 | deploy:
31 | provider: releases
32 | api_key:
33 | secure: xUR2U9bmUTzNmlQoUmiPhP++vsO25W4xBTs6aXMZ2/D+6hkCbh47SKgYuSPV/Fh2HMBqz+dxqe8xk9tt+MGKY3WwjbVbWE8f2rsFNdH4i6XPJiwROG5M+mz/jXAP63R65Uq2lCuUHTUxT6lcEj7jfyQqlyY51e5lg1zepywSUslhE5Q3Ji9fCDY4cMKhO5y16tTMDnlN/W5UA1nKCMH5JCuKYgA9IKwWzx7Wm9WqoN+4P8/4BZiZYkvG7nN1utNzi3feEX4A2MEj7Vs8mcfCpa5QOEQi2d6+abqk7yCZYB5nMn+M2glTeFw305i8OzUdsNhYHdSFZpqos8kH3iSxmg6xWE30mW53kkNSYVW4sqw12xeNgxKaK9ByDUxdqCVdWopOB+wDfkdPyhQ3yI/dtyLNRz9qbKJuHFyN7NDnhpdMs0nqyGgKSIDWf3hZBpp4rCZ66fAYeUGr1Zv++9z8Tje/xgZM3XThtBZyC5ojP14n0SXql/fBv8P58Hq0FCAldxkhshK444jvsMvEmgpa98kalOG9hT862rTsPK73F/hx+CclgI6usk30PagSNIjLlqyNy5Bz9dzvsfczqmiFscp+xxaCHuV8j/ipomvkamhUnNB2snmQ+oqtRUdV3XDRnaYwsyc3IdHwQqHSds55ydxJ82fPB07g41NXYBIeNUQ=
34 | file: app/build/outputs/apk/debug/app-debug.apk
35 | skip_cleanup: true
36 | on:
37 | tags: true
38 |
39 |
--------------------------------------------------------------------------------
/README-zh.md:
--------------------------------------------------------------------------------
1 | # v2ex-simple
2 |
3 | 顾名思义,这是一款简单的v2ex第三方Android客户端。
4 |
5 | ## 现状
6 |
7 | 该项目应该不会有大的功能更新了,仅修复bug。如有问题,欢迎提出。
8 |
9 |
10 | [](https://travis-ci.org/fan123199/v2ex-simple)
11 |
12 | ## Google Play
13 |
14 | [](https://play.google.com/store/apps/details?id=im.fdx.v2ex)
15 |
16 |
17 |
18 | ## 主要功能
19 |
20 | + 浏览V2EX的内容
21 | + 发表文章和回复
22 | + 从web打开应用
23 | + 后台获取更新
24 | + 夜间模式
25 | + 文字大小配置
26 | + 搜索文章
27 |
28 | ## 用到的第三方库
29 |
30 | + Firebase
31 | + Glide4
32 | + OkHttp3
33 | + Firebase
34 | + Flexbox
35 | + Gson
36 | + Anko
37 | + CircleImageView
38 | + Jsoup
39 | + ...
40 |
41 | ## 鸣谢
42 |
43 | + [greatyao/v2ex-android](https://github.com/greatyao/v2ex-android/tree/master)
44 | 这是我的入门指导,当时还什么都不会。
45 | + 部分UI 由 Evermoon 设计完成 [weibo_link](http://weibo.com/evermoon30964)
46 |
47 | ## 开源许可证
48 |
49 | Copyright 2017 fan123199
50 |
51 | Licensed under the Apache License, Version 2.0 (the "License");
52 | you may not use this file except in compliance with the License.
53 | You may obtain a copy of the License at
54 |
55 | http://www.apache.org/licenses/LICENSE-2.0
56 |
57 | Unless required by applicable law or agreed to in writing, software
58 | distributed under the License is distributed on an "AS IS" BASIS,
59 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
60 | See the License for the specific language governing permissions and
61 | limitations under the License.
62 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # v2ex-simple
2 | A simple android client for exploring V2EX. Excellent user experience.
3 | Project is first written by Java and now kotlin.
4 |
5 | [中文Readme](./README-zh.md)
6 |
7 | ## status
8 |
9 | The project would will be less feature update, only bug fixed. But you have any issue, I'd like to help you.
10 |
11 | [](https://travis-ci.org/fan123199/v2ex-simple)
12 |
13 | ## Download
14 |
15 | [
](https://f-droid.org/packages/im.fdx.v2ex/)
18 | [
](https://play.google.com/store/apps/details?id=im.fdx.v2ex)
21 |
22 | ## Main function
23 |
24 | + show v2ex topic content
25 | + create topic and make comment
26 | + open from web url
27 | + unread message through background
28 | + night mode
29 | + font size customized
30 | + search topic
31 |
32 | ## 3rd libraries
33 |
34 | + Firebase
35 | + Glide4
36 | + OkHttp3
37 | + Firebase
38 | + Flexbox
39 | + Gson
40 | + Anko
41 | + CircleImageView
42 | + Jsoup
43 | + ...
44 |
45 | ## Thanks
46 |
47 | + [greatyao/v2ex-android](https://github.com/greatyao/v2ex-android/tree/master)
48 | The project guide me to start this project from zero.
49 | + *twitter/v2ex+/weico/...* is learned for excellent user experience
50 | + UI mostly designed by Evermoon [weibo_link](http://weibo.com/evermoon30964)
51 |
52 | ## License
53 |
54 | Copyright 2017 fan123199
55 |
56 | Licensed under the Apache License, Version 2.0 (the "License");
57 | you may not use this file except in compliance with the License.
58 | You may obtain a copy of the License at
59 |
60 | http://www.apache.org/licenses/LICENSE-2.0
61 |
62 | Unless required by applicable law or agreed to in writing, software
63 | distributed under the License is distributed on an "AS IS" BASIS,
64 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
65 | See the License for the specific language governing permissions and
66 | limitations under the License.
67 |
--------------------------------------------------------------------------------
/app/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "517796818811",
4 | "firebase_url": "https://v2ex-simple.firebaseio.com",
5 | "project_id": "v2ex-simple",
6 | "storage_bucket": "v2ex-simple.appspot.com"
7 | },
8 | "client": [
9 | {
10 | "client_info": {
11 | "mobilesdk_app_id": "1:517796818811:android:6384266b081c14be",
12 | "android_client_info": {
13 | "package_name": "im.fdx.v2ex"
14 | }
15 | },
16 | "oauth_client": [
17 | {
18 | "client_id": "517796818811-be2ttlkv98gc3vats7ieht83qgj05t86.apps.googleusercontent.com",
19 | "client_type": 1,
20 | "android_info": {
21 | "package_name": "im.fdx.v2ex",
22 | "certificate_hash": "8197be9af81d80ebd15ef8f411c322503bbee853"
23 | }
24 | },
25 | {
26 | "client_id": "517796818811-ff8hd6s820c6gugrq9tpeicrd071v8f5.apps.googleusercontent.com",
27 | "client_type": 3
28 | }
29 | ],
30 | "api_key": [
31 | {
32 | "current_key": "AIzaSyBs6Rm6Fa7GTg2vRXSIwYo5fb4PkPY2HGQ"
33 | }
34 | ],
35 | "services": {
36 | "appinvite_service": {
37 | "other_platform_oauth_client": [
38 | {
39 | "client_id": "517796818811-ff8hd6s820c6gugrq9tpeicrd071v8f5.apps.googleusercontent.com",
40 | "client_type": 3
41 | }
42 | ]
43 | }
44 | }
45 | },
46 | {
47 | "client_info": {
48 | "mobilesdk_app_id": "1:517796818811:android:77a9c1e989fda93d2457de",
49 | "android_client_info": {
50 | "package_name": "im.fdx.v2ex.debug"
51 | }
52 | },
53 | "oauth_client": [
54 | {
55 | "client_id": "517796818811-ff8hd6s820c6gugrq9tpeicrd071v8f5.apps.googleusercontent.com",
56 | "client_type": 3
57 | }
58 | ],
59 | "api_key": [
60 | {
61 | "current_key": "AIzaSyBs6Rm6Fa7GTg2vRXSIwYo5fb4PkPY2HGQ"
62 | }
63 | ],
64 | "services": {
65 | "appinvite_service": {
66 | "other_platform_oauth_client": [
67 | {
68 | "client_id": "517796818811-ff8hd6s820c6gugrq9tpeicrd071v8f5.apps.googleusercontent.com",
69 | "client_type": 3
70 | }
71 | ]
72 | }
73 | }
74 | }
75 | ],
76 | "configuration_version": "1"
77 | }
--------------------------------------------------------------------------------
/app/src/debug/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | v2ex-beta
4 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/app/src/main/ic_notification_icon-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/ic_notification_icon-web.png
--------------------------------------------------------------------------------
/app/src/main/ic_settings-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/ic_settings-web.png
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/MyApp.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex
2 |
3 | import android.app.Application
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.content.SharedPreferences
7 | import androidx.appcompat.app.AppCompatDelegate.*
8 | import androidx.core.content.edit
9 | import androidx.localbroadcastmanager.content.LocalBroadcastManager
10 | import com.elvishew.xlog.LogLevel
11 | import com.elvishew.xlog.XLog
12 | import im.fdx.v2ex.network.HttpHelper
13 | import im.fdx.v2ex.network.cookie.SharedPrefsPersistor
14 | import im.fdx.v2ex.utils.Keys
15 | import im.fdx.v2ex.utils.extensions.logd
16 | import java.net.HttpCookie
17 |
18 | val pref: SharedPreferences by lazy {
19 | androidx.preference.PreferenceManager.getDefaultSharedPreferences(myApp)
20 | }
21 |
22 | @Deprecated("技术困难,下一期实现")
23 | val userPref: SharedPreferences by lazy {
24 | val fileName = pref.getString(Keys.KEY_USERNAME, "user")
25 | myApp.getSharedPreferences(fileName, Context.MODE_PRIVATE)
26 | }
27 |
28 | val myApp: MyApp by lazy {
29 | MyApp.get()
30 | }
31 |
32 | /**
33 | * Created by fdx on 2015/8/16.
34 | * 用于启动时获取app状态
35 | */
36 | class MyApp : Application() {
37 |
38 | companion object {
39 | private lateinit var INSTANCE: MyApp
40 | internal fun get(): MyApp {
41 | return INSTANCE
42 | }
43 | }
44 | internal var isLogin = false
45 |
46 | override fun onCreate() {
47 | super.onCreate()
48 | INSTANCE = this
49 | XLog.init(when {
50 | BuildConfig.DEBUG -> LogLevel.ALL
51 | else -> LogLevel.NONE
52 | })
53 | isLogin = pref.getBoolean(Keys.PREF_KEY_IS_LOGIN, false)
54 |
55 |
56 | pref.edit {
57 | putInt(Keys.PREF_APP_PREF_VERSION, BuildConfig.VERSION_CODE)
58 | }
59 | //后续做sp的版本判断在这里
60 | logd("onCreate\nisLogin:$isLogin")
61 |
62 | setDefaultNightMode(pref.getString(Keys.PREF_NIGHT_MODE, MODE_NIGHT_NO.toString())!!.toInt())
63 | }
64 | }
65 |
66 | fun setLogin(login: Boolean) {
67 | myApp.isLogin = login
68 | pref.edit {
69 | putBoolean(Keys.PREF_KEY_IS_LOGIN, login)
70 | }
71 | if(!login){
72 | HttpHelper.myCookieJar.clear()
73 | }
74 | LocalBroadcastManager.getInstance(myApp).sendBroadcast(
75 | if (login){
76 | Intent(Keys.ACTION_LOGIN)
77 | } else {
78 | Intent(Keys.ACTION_LOGOUT)
79 | })
80 | }
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/MyGlideModule.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex
2 |
3 | import com.bumptech.glide.annotation.GlideModule
4 | import com.bumptech.glide.module.AppGlideModule
5 |
6 | /**
7 | * Created by fdx on 2017/8/29.
8 | *
9 | */
10 | @GlideModule
11 | class MyGlideModule : AppGlideModule()
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/database/AppDatabase.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.database
2 |
3 | import androidx.room.Database
4 | import androidx.room.RoomDatabase
5 | import im.fdx.v2ex.ui.topic.MyReply
6 | import im.fdx.v2ex.ui.topic.MyReplyDao
7 | import im.fdx.v2ex.ui.main.Topic
8 | import im.fdx.v2ex.ui.main.TopicDao
9 | import im.fdx.v2ex.ui.node.Node
10 | import im.fdx.v2ex.ui.node.NodeDao
11 |
12 |
13 | @Database(entities = [Topic::class, Node::class, MyReply::class], version = 5, exportSchema = false)
14 | abstract class AppDatabase : RoomDatabase() {
15 | abstract fun topicDao(): TopicDao
16 | abstract fun nodeDao(): NodeDao
17 | abstract fun myReplyDao(): MyReplyDao
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/database/DbHelper.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.database
2 |
3 | import androidx.room.Room
4 | import im.fdx.v2ex.MyApp
5 |
6 |
7 | object DbHelper {
8 |
9 | var db = Room.databaseBuilder(MyApp.get(), AppDatabase::class.java, "v2ex.db")
10 | .fallbackToDestructiveMigration()
11 | .build()
12 | }
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/model/Data.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.model
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class Data(
6 |
7 | @field:SerializedName("path")
8 | val path: String? = null,
9 |
10 | @SerializedName("filename")
11 | val filename: String? = null,
12 |
13 | @SerializedName("size")
14 | val size: Int? = null,
15 |
16 | @SerializedName("ip")
17 | val ip: String? = null,
18 |
19 | @SerializedName("width")
20 | val width: Int? = null,
21 |
22 | @SerializedName("storename")
23 | val storename: String? = null,
24 |
25 | @SerializedName("delete")
26 | val delete: String? = null,
27 |
28 | @SerializedName("hash")
29 | val hash: String? = null,
30 |
31 | @SerializedName("url")
32 | val url: String? = null,
33 |
34 | @SerializedName("height")
35 | val height: Int? = null,
36 |
37 | @SerializedName("timestamp")
38 | val timestamp: Int? = null,
39 | val msg: String? = null
40 | )
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/model/NotificationModel.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.model
2 |
3 | import android.os.Parcelable
4 | import im.fdx.v2ex.ui.main.Topic
5 | import im.fdx.v2ex.ui.member.Member
6 | import kotlinx.parcelize.Parcelize
7 |
8 | /**
9 | * Created by fdx on 2017/3/24.
10 | */
11 |
12 | @Parcelize
13 | class NotificationModel(var time: String? = "",
14 | var replyPosition: String? = "",
15 | var type: String? = "",
16 | var topic: Topic? = Topic(),
17 | var member: Member? = Member(),
18 | var content: String? = "",
19 | var id: String? = "") : Parcelable, VModel()
20 |
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/model/Res.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.model
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class Res(
6 |
7 | @field:SerializedName("code")
8 | val code: String? = null,
9 |
10 | @field:SerializedName("data")
11 | val data: Data? = null
12 | )
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/model/VModel.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.model
2 |
3 |
4 | /**
5 | * used for proguard
6 | */
7 | abstract class VModel
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/network/GetMoreRepliesWorker.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.network
2 |
3 | import android.app.*
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.os.Build
7 | import androidx.core.app.NotificationCompat
8 | import androidx.core.content.ContextCompat
9 | import androidx.localbroadcastmanager.content.LocalBroadcastManager
10 | import androidx.work.Worker
11 | import androidx.work.WorkerParameters
12 | import com.elvishew.xlog.XLog
13 | import im.fdx.v2ex.R
14 | import im.fdx.v2ex.ui.NotificationActivity
15 | import im.fdx.v2ex.utils.Keys
16 | import im.fdx.v2ex.utils.extensions.logd
17 | import okhttp3.Call
18 | import okhttp3.Callback
19 | import okhttp3.Response
20 | import java.io.IOException
21 |
22 | class GetMoreRepliesWorker(val context: Context, workerParameters: WorkerParameters) : Worker(context, workerParameters) {
23 | override fun doWork(): Result {
24 |
25 | getAllMore()
26 |
27 | return Result.success()
28 |
29 | }
30 | private fun getAllMore() {
31 | val totalPage = inputData.getInt("page", -1)
32 | val topicId = inputData.getString("topic_id")
33 | val isToBottom = inputData.getBoolean("bottom", false)
34 |
35 | logd("$totalPage | $topicId")
36 | if (totalPage <= 1 || topicId == null) {
37 | return
38 | }
39 |
40 | try {
41 | for (i in 2..totalPage) {
42 | val response = vCall("${NetManager.HTTPS_V2EX_BASE}/t/$topicId?p=$i").execute()
43 | val parser = Parser(response.body!!.string())
44 | val replies = parser.getReplies()
45 |
46 | if (replies.isEmpty()) return
47 | val replyIntent = Intent()
48 | replyIntent.action = Keys.ACTION_GET_MORE_REPLY
49 | replyIntent.putExtra(Keys.KEY_TOPIC_ID, topicId)
50 | replyIntent.putParcelableArrayListExtra("replies", replies)
51 |
52 | if (i == totalPage && isToBottom) {
53 | replyIntent.putExtra("bottom", true)
54 | }
55 | LocalBroadcastManager.getInstance(context).sendBroadcast(replyIntent)
56 | }
57 |
58 | } catch (e: IOException) {
59 | e.printStackTrace()
60 | }
61 |
62 | }
63 |
64 | }
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/network/cookie/CookiePersistor.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.network.cookie
2 |
3 | import okhttp3.Cookie
4 |
5 | /**
6 | * Created by fdx on 2017/3/16.
7 | */
8 |
9 | interface CookiePersistor {
10 |
11 | fun removeAll(cookies: List)
12 |
13 | fun clear()
14 |
15 | fun persist(cookie: Cookie)
16 |
17 | fun persistAll(cookies: Collection)
18 |
19 | fun loadAll(): List
20 |
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/network/cookie/MyCookieJar.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.network.cookie
2 |
3 | import okhttp3.Cookie
4 | import okhttp3.CookieJar
5 | import okhttp3.HttpUrl
6 | import java.util.*
7 |
8 | /**
9 | * Created by fdx on 2017/3/16.
10 | *
11 | *
12 | * 请用自己的Cookie策略,而不是开源库。
13 | */
14 | class MyCookieJar(private val cookiePersistor: SharedPrefsPersistor) : CookieJar {
15 | private val cookieStore = HashMap>()
16 | private val mCookies = ArrayList()
17 |
18 | override fun saveFromResponse(url: HttpUrl, cookies: List) {
19 | mCookies.clear()
20 | mCookies.addAll(cookies)
21 | cookieStore[url.host] = mCookies
22 | cookiePersistor.persistAll(cookies)
23 | }
24 |
25 | override fun loadForRequest(url: HttpUrl): List {
26 |
27 | val cookies: List? = if (cookiePersistor.loadByHost(url.host).isNotEmpty()) {
28 | cookiePersistor.loadByHost(url.host.removePrefix("www."))
29 | } else
30 | cookieStore[url.host]
31 | return cookies ?: ArrayList()
32 | }
33 |
34 | fun clear() {
35 | mCookies.clear()
36 | cookieStore.clear()
37 | cookiePersistor.clear()
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/ui/BaseFragment.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.ui
2 |
3 | import androidx.fragment.app.Fragment
4 |
5 | /**
6 | * Create by fandongxiao on 2019/5/16
7 | */
8 | open class BaseFragment : Fragment() {
9 | }
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/ui/MyCallback.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.ui
2 |
3 | import androidx.recyclerview.widget.ListUpdateCallback
4 | import im.fdx.v2ex.ui.main.TopicsRVAdapter
5 |
6 |
7 | /**
8 | * Created by fdx on 2017/7/25.
9 | *
10 | */
11 | internal class MyCallback(var adapter: TopicsRVAdapter) : ListUpdateCallback {
12 | var firstInsert = -1
13 |
14 | override fun onChanged(position: Int, count: Int, payload: Any?) {
15 | adapter.notifyItemRangeChanged(position, count, payload)
16 | }
17 |
18 | override fun onInserted(position: Int, count: Int) {
19 | if (firstInsert == -1 || firstInsert > position) {
20 | firstInsert = position
21 | }
22 | adapter.notifyItemRangeInserted(position, count)
23 | }
24 |
25 | override fun onMoved(fromPosition: Int, toPosition: Int) {
26 | adapter.notifyItemMoved(fromPosition, toPosition)
27 | }
28 |
29 | override fun onRemoved(position: Int, count: Int) {
30 | adapter.notifyItemRangeRemoved(position, count)
31 | }
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/ui/TestActivity.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.ui
2 |
3 | import android.os.Bundle
4 | import android.os.PersistableBundle
5 | import android.telephony.PhoneNumberFormattingTextWatcher
6 | import android.telephony.PhoneNumberUtils
7 | import im.fdx.v2ex.R
8 | import im.fdx.v2ex.utils.extensions.logi
9 | import im.fdx.v2ex.utils.extensions.toast
10 | import java.util.*
11 |
12 | class TestActivity : BaseActivity() {
13 |
14 |
15 | override fun onCreate(savedInstanceState: Bundle?) {
16 | super.onCreate(savedInstanceState)
17 |
18 | setContentView(R.layout.activity_test)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/ui/favor/FavorActivity.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.ui.favor
2 |
3 | import android.os.Bundle
4 | import android.view.MotionEvent
5 | import androidx.viewpager.widget.ViewPager
6 | import androidx.viewpager2.widget.ViewPager2
7 | import com.google.android.material.tabs.TabLayout
8 | import com.google.android.material.tabs.TabLayoutMediator
9 | import im.fdx.v2ex.R
10 | import im.fdx.v2ex.ui.BaseActivity
11 | import im.fdx.v2ex.ui.favor.FavorViewPagerAdapter.Companion.titles
12 | import im.fdx.v2ex.ui.tabTitles
13 | import im.fdx.v2ex.utils.extensions.setUpToolbar
14 | import im.fdx.v2ex.view.ViewPagerHelper
15 | import kotlin.math.abs
16 |
17 | class FavorActivity : BaseActivity() {
18 | private var helper: ViewPagerHelper? = null
19 | lateinit var viewPager: ViewPager2
20 | lateinit var tabLayout: TabLayout
21 | override fun onCreate(savedInstanceState: Bundle?) {
22 | super.onCreate(savedInstanceState)
23 | setContentView(R.layout.activity_follow_activity)
24 |
25 | setUpToolbar(getString(R.string.my_follow))
26 |
27 |
28 | tabLayout = findViewById(R.id.tl_favor)
29 | viewPager = findViewById(R.id.viewpager_follow)
30 | viewPager.offscreenPageLimit = titles.size
31 | viewPager.adapter = FavorViewPagerAdapter(this)
32 | TabLayoutMediator(tabLayout, viewPager) { tab, position ->
33 | tab.text = titles[position]
34 | }.attach()
35 |
36 | helper = ViewPagerHelper(viewPager)
37 |
38 | }
39 |
40 |
41 | override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
42 | helper?.dispatchTouchEvent(ev)
43 | return super.dispatchTouchEvent(ev)
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/ui/favor/FavorViewPagerAdapter.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.ui.favor
2 |
3 | import android.os.Bundle
4 | import androidx.core.os.bundleOf
5 | import androidx.fragment.app.Fragment
6 | import androidx.fragment.app.FragmentActivity
7 | import androidx.viewpager.widget.PagerAdapter
8 | import androidx.viewpager2.adapter.FragmentStateAdapter
9 | import im.fdx.v2ex.ui.main.TopicsFragment
10 | import im.fdx.v2ex.utils.Keys
11 |
12 | /**
13 | * Created by fdx on 2017/4/13.
14 | */
15 | internal class FavorViewPagerAdapter(fa: FragmentActivity) : FragmentStateAdapter(fa) {
16 |
17 | companion object {
18 | val titles = arrayOf("节点收藏", "主题收藏", "特别关注")
19 | }
20 |
21 | override fun getItemCount(): Int {
22 | return titles.size
23 | }
24 |
25 | override fun createFragment(position: Int): Fragment {
26 | return when (position) {
27 | 0 -> NodeFavorFragment()
28 | 1 -> {
29 | TopicsFragment().apply {
30 | arguments = bundleOf(Keys.FAVOR_FRAGMENT_TYPE to position)
31 | }
32 | }
33 | 2 -> {
34 | TopicsFragment().apply {
35 | arguments = bundleOf(Keys.FAVOR_FRAGMENT_TYPE to position)
36 | }
37 | }
38 | else -> throw Exception()
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/ui/main/Comment.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.ui.main
2 |
3 | import android.os.Parcelable
4 | import im.fdx.v2ex.model.VModel
5 | import kotlinx.parcelize.Parcelize
6 |
7 | @Parcelize
8 | data class Comment(var title: String = "",
9 | var created: Long = 0,
10 | var createdOriginal: String = "",
11 | var content: String = "") : Parcelable, VModel()
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/ui/main/MyDiffCallback.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.ui.main
2 |
3 | import androidx.recyclerview.widget.DiffUtil
4 |
5 | /**
6 | * Created by fdx on 2017/7/11.
7 | * fdx will maintain it
8 | */
9 | class MyDiffCallback(private val oldList: List, private val newList: List) : DiffUtil.Callback() {
10 |
11 | override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
12 | return oldList[oldItemPosition].id == newList[newItemPosition].id
13 | }
14 |
15 | override fun getOldListSize() = oldList.size
16 | override fun getNewListSize() = newList.size
17 |
18 | /**
19 | * 有点问题,GoodText不加载图片
20 | */
21 | override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
22 | return oldList[oldItemPosition].replies == newList[newItemPosition].replies &&
23 | oldList[oldItemPosition].content_rendered == newList[newItemPosition].content_rendered
24 | }
25 |
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/ui/main/MyViewPagerAdapter.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.ui.main
2 |
3 | import androidx.core.os.bundleOf
4 | import androidx.fragment.app.Fragment
5 | import androidx.fragment.app.FragmentActivity
6 | import androidx.viewpager2.adapter.FragmentStateAdapter
7 | import com.google.gson.Gson
8 | import com.google.gson.reflect.TypeToken
9 | import im.fdx.v2ex.myApp
10 | import im.fdx.v2ex.pref
11 | import im.fdx.v2ex.ui.MyTab
12 | import im.fdx.v2ex.ui.tabPaths
13 | import im.fdx.v2ex.ui.tabTitles
14 | import im.fdx.v2ex.utils.Keys
15 | import im.fdx.v2ex.utils.Keys.PREF_TAB
16 | import java.util.*
17 |
18 |
19 | /**
20 | * Created by fdx on 2015/10/15.
21 | * 从MainActivity分离出来. 用了FragmentStatePagerAdapter 替代FragmentPagerAdapter,才可以动态切换Fragment
22 | * 弃用了Volley 和 模拟web + okhttp
23 | *
24 | * todo pageadapter有更新,明天需要完成
25 | */
26 | internal class MyViewPagerAdapter(
27 | fa: FragmentActivity) : FragmentStateAdapter(fa) {
28 |
29 | private val mFragments = ArrayList()
30 | val myTabList = mutableListOf()
31 | init {
32 | initFragment()
33 | }
34 |
35 | fun initFragment() {
36 | myTabList.clear()
37 | mFragments.clear()
38 |
39 | var jsonData = pref.getString(PREF_TAB, null)
40 | if (jsonData == null) {
41 | val list = MutableList(tabTitles.size) { index: Int ->
42 | MyTab(tabTitles[index], tabPaths[index])
43 | }
44 |
45 | jsonData = Gson().toJson(list)
46 | }
47 |
48 | val turnsType = object : TypeToken>() {}.type
49 | val list = Gson().fromJson>(jsonData, turnsType)
50 |
51 | if(list.isNullOrEmpty()) { //可能的一些奇怪的问题
52 | MutableList(tabTitles.size) { index: Int ->
53 | MyTab(tabTitles[index], tabPaths[index])
54 | }
55 | }
56 |
57 | for (it in list) {
58 | if (!myApp.isLogin && it.path == "recent") {
59 | continue
60 | }
61 | mFragments.add(TopicsFragment().apply { arguments = bundleOf(Keys.KEY_TAB to it.path, Keys.KEY_TYPE to it.type) })
62 | myTabList.add(it)
63 | }
64 | }
65 |
66 | override fun getItemCount(): Int {
67 | return myTabList.size + 1
68 | }
69 |
70 | override fun createFragment(position: Int): Fragment {
71 | return if (position < itemCount -1)
72 | mFragments[position]
73 | else
74 | Fragment()
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/ui/main/TopicDao.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.ui.main
2 |
3 | import androidx.room.*
4 |
5 |
6 | @Dao
7 | interface TopicDao {
8 |
9 | // @Insert(onConflict = OnConflictStrategy.REPLACE)
10 | // fun insertTopic(vararg topics: Topic)
11 | //
12 | // @Insert
13 | // fun insertBothTopic(topic1: Topic, topic2: Topic)
14 | //
15 | // @Update
16 | // fun updateTopic(vararg topic: Topic)
17 | //
18 | // @Delete
19 | // fun deleteTopic(vararg topic: Topic)
20 | //
21 | //
22 | // @Query("SELECT * FROM topic WHERE replies > :replyNum")
23 | // fun loadAllUsersOlderThan(replyNum: Int): List
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/ui/main/model/SearchResult.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.ui.main.model
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class SearchResult(
6 |
7 | @SerializedName("hits")
8 | val hits: List? = null,
9 |
10 | @SerializedName("took")
11 | val took: Int? = null,
12 |
13 | @SerializedName("total")
14 | val total: Int? = null,
15 |
16 | @SerializedName("timed_out")
17 | val timedOut: Boolean? = null
18 | )
19 |
20 | data class HitsItem(
21 |
22 | @SerializedName("highlight")
23 | val highlight: Highlight? = null,
24 |
25 | @SerializedName("_index")
26 | val index: String? = null,
27 |
28 | @SerializedName("_type")
29 | val type: String? = null,
30 |
31 | @SerializedName("_source")
32 | val source: Source? = null,
33 |
34 | @SerializedName("_id")
35 | val id: String? = null,
36 |
37 | @SerializedName("_score")
38 | val score: Double? = null
39 | )
40 |
41 | data class Source(
42 |
43 | @SerializedName("node")
44 | val node: Int? = null,
45 |
46 | @SerializedName("replies")
47 | val replies: Int? = null,
48 |
49 | @SerializedName("created")
50 | val created: String? = null,
51 |
52 | @SerializedName("member")
53 | val member: String? = null,
54 |
55 | @SerializedName("id")
56 | val id: Int? = null,
57 |
58 | @SerializedName("title")
59 | val title: String? = null,
60 |
61 | @SerializedName("content")
62 | val content: String? = null
63 | )
64 | data class Highlight(
65 |
66 | @SerializedName("reply_list.content")
67 | val replyListContent: List? = null,
68 |
69 | @SerializedName("title")
70 | val title: List? = null,
71 |
72 | @SerializedName("postscript_list.content")
73 | val postscriptListContent: List? = null,
74 |
75 | @SerializedName("content")
76 | val content: List? = null
77 | )
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/ui/member/DiffReply.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.ui.member
2 |
3 | import androidx.recyclerview.widget.DiffUtil
4 |
5 | /**
6 | * Created by fdx on 2017/7/31.
7 | *
8 | */
9 | class DiffReply(val oldList: List, val newList: List) : DiffUtil.Callback() {
10 |
11 | override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int)
12 | = oldList[oldItemPosition].content == newList[newItemPosition].content
13 |
14 | override fun getOldListSize() = oldList.size
15 | override fun getNewListSize() = newList.size
16 |
17 | /**
18 | * 有点问题,GoodText不加载图片
19 | */
20 | override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int)
21 | = oldList[oldItemPosition].content == newList[newItemPosition].content
22 |
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/ui/member/Member.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.ui.member
2 |
3 | import android.os.Parcelable
4 | import androidx.room.ColumnInfo
5 | import kotlinx.parcelize.Parcelize
6 |
7 | /**
8 | * Created by a708 on 16-1-16.
9 | * V2ex 的 个人信息 模型
10 |
11 | * username 和 id 都是 key value
12 | */
13 |
14 | //{
15 | // "status" : "found",
16 | // "id" : 32044,
17 | // "url" : "http://www.v2ex.com/member/cxshun",
18 | // "username" : "cxshun",
19 | // "website" : "http://www.chenxiaoshun.com/",
20 | // "twitter" : "cxshun",
21 | // "psn" : "",
22 | // "github" : "cxshun",
23 | // "btc" : "",
24 | // "location" : "",
25 | // "tagline" : "",
26 | // "bio" : "",
27 | // "avatar_mini" : "//cdn.v2ex.com/gravatar/273313b23fdf59a7695f46c6ae175776?s=24&d=retro,
28 | // 部分新域名, 部分旧域名 cdn.v2ex.com/avatar/00a6/7ce3/279733_mini.png?m=1546517640
29 | // "avatar_normal" : "//cdn.v2ex.com/gravatar/273313b23fdf59a7695f46c6ae175776?s=24&d=retro",
30 | // 有坑,现在都是返回小图。
31 | // "avatar_large" : "//cdn.v2ex.com/gravatar/273313b23fdf59a7695f46c6ae175776?s=24&d=retro",
32 | // "created" : 1357733451
33 | // }
34 |
35 | @Parcelize
36 | data class Member(
37 | @ColumnInfo(name = "member_id")
38 | var id: String = "",
39 | var username: String = "",
40 | var tagline: String? = "",
41 | @ColumnInfo(name = "member_created")
42 | var created: String = "",
43 | @ColumnInfo(name = "member_avatar_normal")
44 | var avatar_normal: String = "",
45 | var bio: String? = "",
46 | var github: String? = "",
47 | var btc: String? = "",
48 | var location: String? = "",
49 | var twitter: String? = "",
50 | var website: String? = ""
51 | ) : Parcelable {
52 |
53 | val avatarNormalUrl: String? //为了减少在sov2ex 的页面的报错,因为他的接口不返回头像
54 | get() {
55 | if(avatar_normal == "") return null
56 |
57 | val prefix = if (avatar_normal.startsWith("https:")) "" else "https:"
58 | return prefix + Regex("\\?s=\\d{1,3}").replace(avatar_normal, "?s=64")
59 | }
60 |
61 | val avatarLargeUrl: String
62 | get() {
63 | val prefix = if (avatar_normal.startsWith("https:")) "" else "https:"
64 | return prefix + Regex("\\?s=\\d{1,3}").replace(avatar_normal, "?s=128").replace("normal","large").replace("mini","large")
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/ui/member/MemberReplyModel.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.ui.member
2 |
3 | import android.os.Parcelable
4 | import im.fdx.v2ex.ui.main.Topic
5 | import kotlinx.parcelize.Parcelize
6 |
7 | /**
8 | * Created by fdx on 2017/7/16.
9 | * fdx will maintain it
10 | */
11 | @Parcelize
12 | data class MemberReplyModel(var id: String? = "",
13 | var topic: Topic = Topic(),
14 | var content: String? = null,
15 | var createdOriginal: String = "",
16 | var create: Long = 0L) : Parcelable
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/ui/member/ReplyAdapter.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.ui.member
2 |
3 | import android.app.Activity
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.TextView
8 | import androidx.recyclerview.widget.DiffUtil
9 | import im.fdx.v2ex.R
10 | import im.fdx.v2ex.ui.topic.TopicActivity
11 | import im.fdx.v2ex.utils.Keys
12 | import im.fdx.v2ex.utils.TimeUtil
13 | import im.fdx.v2ex.view.GoodTextView
14 | import im.fdx.v2ex.utils.extensions.startActivity
15 |
16 | /**
17 | * Created by fdx on 2017/7/15.
18 | * fdx will maintain it
19 | * 在用户信息的回复页面
20 | */
21 | class ReplyAdapter(val activity: Activity,
22 | var list: MutableList = mutableListOf())
23 | : androidx.recyclerview.widget.RecyclerView.Adapter() {
24 |
25 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
26 | ReplyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_reply_member, parent, false))
27 |
28 | override fun onBindViewHolder(holder: ReplyViewHolder, position: Int) {
29 |
30 | val reply = list[position]
31 | holder.tvTitle.text =reply.createdOriginal + " 回复了主题:\n" + reply.topic.title
32 | holder.tvContent.setGoodText(reply.content, true)
33 | // holder.tvTime.text = reply.createdOriginal
34 |
35 | holder.itemView.setOnClickListener {
36 | activity.startActivity(Keys.KEY_TOPIC_ID to reply.topic.id)
37 | }
38 | }
39 |
40 |
41 | fun updateItem(newItems: List) {
42 | // val diffResult = DiffUtil.calculateDiff(DiffReply(list, newItems))
43 | list.clear()
44 | list.addAll(newItems)
45 | notifyDataSetChanged()
46 | // diffResult.dispatchUpdatesTo(this)
47 |
48 | }
49 |
50 | fun addItems(newItems: List) {
51 | val old = list.toList()
52 | list.addAll(newItems)
53 | val diffResult = DiffUtil.calculateDiff(DiffReply(old, list))
54 | diffResult.dispatchUpdatesTo(this)
55 | }
56 |
57 | override fun getItemCount() = list.size
58 |
59 | inner class ReplyViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView) {
60 | val tvTitle: TextView = itemView.findViewById(R.id.tv_title)
61 | val tvContent: GoodTextView = itemView.findViewById(R.id.tv_content_reply)
62 | val tvTime: TextView = itemView.findViewById(R.id.tv_create)
63 | }
64 | }
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/ui/node/AllNodesAdapter.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.ui.node
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import android.widget.ImageView
7 | import android.widget.TextView
8 | import com.elvishew.xlog.XLog
9 | import im.fdx.v2ex.R
10 | import im.fdx.v2ex.utils.Keys
11 | import im.fdx.v2ex.utils.extensions.load
12 | import im.fdx.v2ex.utils.extensions.startActivity
13 | import java.util.*
14 |
15 | /**
16 | * Created by fdx on 2016/9/13.
17 | * 简单节点adapter,用在个人favor
18 | */
19 | class AllNodesAdapter(val isShowImg: Boolean = false) : androidx.recyclerview.widget.RecyclerView.Adapter() {
20 |
21 | private var mNodes: MutableList = ArrayList()
22 | private var realAllNodes: MutableList = ArrayList()
23 |
24 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
25 | AllNodeViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_all_nodes, parent, false))
26 |
27 | override fun onBindViewHolder(holder: AllNodeViewHolder, position: Int) {
28 | XLog.tag("RV_INNER").e("$position")
29 | val node = mNodes[position]
30 |
31 | if (isShowImg) holder.ivNodeIcon.load(node.avatarLargeUrl)
32 | else {
33 | holder.ivNodeIcon.visibility = View.GONE
34 | }
35 | holder.tvNodeName.text = node.title
36 | holder.itemView.setOnClickListener {
37 | it.context.startActivity(Keys.KEY_NODE_NAME to node.name)
38 | }
39 |
40 | }
41 |
42 | override fun getItemCount() = mNodes.size
43 |
44 | fun setAllData(nodes: MutableList) {
45 | mNodes = nodes
46 | realAllNodes = nodes
47 | }
48 |
49 | fun addAll(nodes: List) {
50 | mNodes.addAll(nodes)
51 | }
52 |
53 | fun clear() = mNodes.clear()
54 |
55 | fun filter(newText: String) {
56 |
57 | if (newText.isEmpty()) {
58 | mNodes = realAllNodes
59 | notifyDataSetChanged()
60 | return
61 | }
62 |
63 | mNodes = realAllNodes.filter {
64 | it.name.contains(newText) || it.title.contains(newText) || it.title_alternative.contains(newText)
65 | }.toMutableList()
66 | notifyDataSetChanged()
67 | }
68 |
69 | class AllNodeViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView) {
70 | var tvNodeName: TextView = itemView.findViewById(R.id.tv_node_name)
71 | var ivNodeIcon: ImageView = itemView.findViewById(R.id.iv_node_image)
72 | }
73 | }
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/ui/node/Node.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.ui.node
2 |
3 | import android.os.Parcelable
4 | import androidx.room.ColumnInfo
5 | import androidx.room.Entity
6 | import androidx.room.PrimaryKey
7 | import kotlinx.parcelize.Parcelize
8 |
9 | /**
10 | * Created by a708 on 16-1-17.
11 | * V2ex 节点模型
12 | * 其中 name 是 key value
13 | */
14 |
15 | ///api/topics/show.json
16 | //
17 | // 参数(选其一)
18 | // username 根据用户名取该用户所发表主题
19 | // node_id 根据节点id取该节点下所有主题
20 | // node_name 根据节点名取该节点下所有主题
21 |
22 | //------------------
23 | //{
24 | // "id" : 90,
25 | // "name" : "python",
26 | // "url" : "http://www.v2ex.com/go/python",
27 | // "title" : "Python",
28 | // "title_alternative" : "Python",
29 | // "topics" : 4272,
30 | // "stars" : 3234,
31 | //
32 | // "header" : "这里讨论各种 Python 语言编程话题,也包括 Django,Tornado 等框架的讨论。这里是一个能够帮助你解决实际问题的地方。",
33 | //
34 | //
35 | // "footer" : null,
36 | //
37 | // "created" : 1278683336,
38 | // "avatar_mini" : "//cdn.v2ex.co/navatar/8613/985e/90_mini.png?m=1452823690",
39 | // "avatar_normal" : "//cdn.v2ex.co/navatar/8613/985e/90_normal.png?m=1452823690",
40 | // "avatar_large" : "//cdn.v2ex.co/navatar/8613/985e/90_large.png?m=1452823690"
41 | // }
42 |
43 | @Entity
44 | @Parcelize
45 | data class Node(
46 | @PrimaryKey
47 | @ColumnInfo(name = "node_id")
48 | var id: String = "",
49 | @ColumnInfo(name = "node_name")
50 | var name: String = "", //英文名称
51 | @ColumnInfo(name = "node_url")
52 | var url: String = "",
53 | @ColumnInfo(name = "node_title")
54 | var title: String = "", //展示名称
55 | var title_alternative: String = "",
56 | var topics: Int = 0,
57 | var stars: Int = 0,
58 | @ColumnInfo(name = "node_created")
59 | var created: Long = 0,
60 | @ColumnInfo(name = "node_avatar_normal")
61 | var avatar_normal: String? = "",
62 | var header: String? = "",
63 | var category: String? = "") : Parcelable {
64 |
65 |
66 | val avatarNormalUrl: String
67 | get() = "https:" + Regex("\\?s=\\d{1,3}").replace(avatar_normal?:"", "?s=64")
68 |
69 | val avatarLargeUrl: String
70 | get() = when {
71 | avatar_normal?.startsWith("/static") == true -> "https://www.v2ex.com/static/img/node_large.png"
72 | else -> Regex("\\?s=\\d{1,3}").replace(avatar_normal?:"", "?s=128").replace("normal","large").replace("mini","large")
73 | }
74 |
75 | override fun toString() = "$title / $name"
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/ui/node/NodeDao.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.ui.node
2 |
3 | import androidx.room.Dao
4 | import androidx.room.Insert
5 | import androidx.room.OnConflictStrategy
6 | import androidx.room.Query
7 |
8 | @Dao
9 | interface NodeDao {
10 |
11 |
12 | @Insert(onConflict = OnConflictStrategy.REPLACE)
13 | fun insertNode(vararg nodes: Node)
14 |
15 | @Query("select * from node ")
16 | fun getNodes(): List
17 |
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/ui/node/SimpleNodesTextAdapter.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.ui.node
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import android.widget.TextView
7 | import im.fdx.v2ex.R
8 |
9 | class SimpleNodesTextAdapter(private var mNodes: MutableList, private val action: (Node) -> Unit)
10 | : androidx.recyclerview.widget.RecyclerView.Adapter() {
11 |
12 | override fun onBindViewHolder(holder: SimpleVH, position: Int) {
13 | holder.tvTitle.text = mNodes[position].title
14 | holder.tvTitle.setOnClickListener {
15 | action(mNodes[position])
16 | }
17 | }
18 |
19 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
20 | SimpleVH(LayoutInflater.from(parent.context).inflate(R.layout.item_node_simple, parent, false))
21 |
22 | override fun getItemCount() = mNodes.size
23 |
24 | inner class SimpleVH(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView) {
25 | val tvTitle = itemView as TextView
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/ui/topic/BottomReplyList.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.ui.topic
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.recyclerview.widget.LinearLayoutManager
8 | import androidx.recyclerview.widget.RecyclerView
9 | import com.google.android.material.bottomsheet.BottomSheetDialogFragment
10 | import im.fdx.v2ex.R
11 | import im.fdx.v2ex.databinding.ItemReplyViewBinding
12 |
13 | internal class BottomReplyList(var list: List) : BottomSheetDialogFragment(){
14 |
15 |
16 | companion object {
17 | fun newInstance(list: List): BottomReplyList {
18 | return BottomReplyList(list)
19 | }
20 | }
21 |
22 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
23 |
24 | return inflater.inflate(R.layout.bottom_list_sheet, container, false)
25 | }
26 |
27 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
28 | super.onViewCreated(view, savedInstanceState)
29 | val rv = view.findViewById(R.id.rv)
30 | rv.layoutManager = LinearLayoutManager(rv.context)
31 | rv.adapter = RAdapter(list)
32 | }
33 |
34 | inner class RAdapter(var list: List) : RecyclerView.Adapter() {
35 | override fun getItemCount(): Int {
36 | return list.size
37 | }
38 |
39 | override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
40 | holder.bind(list[position])
41 | }
42 |
43 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
44 | return ItemViewHolder(ItemReplyViewBinding.inflate(LayoutInflater.from(parent.context), parent, false))
45 | }
46 |
47 | }
48 | }
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/ui/topic/MyReply.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.ui.topic
2 |
3 | import androidx.room.*
4 |
5 | @Entity(tableName = "my_reply")
6 | data class MyReply(
7 |
8 | @PrimaryKey
9 | @ColumnInfo(name = "topic_id")
10 | var topicId :String,
11 | @ColumnInfo(name = "content")
12 | var content : String
13 | )
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/ui/topic/MyReplyDao.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.ui.topic
2 |
3 | import androidx.room.Dao
4 | import androidx.room.Insert
5 | import androidx.room.OnConflictStrategy
6 | import androidx.room.Query
7 |
8 | @Dao
9 | interface MyReplyDao {
10 |
11 | @Query("SELECT * FROM my_reply WHERE topic_id = (:topicId)")
12 | suspend fun getMyReplyById(topicId: String) : MyReply?
13 |
14 |
15 | @Insert(onConflict = OnConflictStrategy.REPLACE)
16 | suspend fun insert(myReply: MyReply): Long
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/ui/topic/Reply.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.ui.topic
2 |
3 | import android.os.Parcelable
4 | import im.fdx.v2ex.ui.member.Member
5 | import kotlinx.parcelize.Parcelize
6 |
7 | /**
8 | * Created by a708 on 15-9-8.
9 | * 评论模型,用于传递从JSON获取到的数据。
10 | * 以后将加入添加评论功能。
11 | */
12 |
13 | //{
14 | // "id" : 2826846,
15 | // "thanks" : 0,
16 | // "content" : "关键你是男还是女?",
17 | // "content_rendered" : "关键你是男还是女?",
18 | // "member" : {
19 | // "id" : 27619,
20 | // "username" : "hengzhang",
21 | // "tagline" : "我白天是个民工,晚上就是个有抱负的IT人士。",
22 | // "avatar_mini" : "//cdn.v2ex.co/avatar/d165/7a2a/27619_mini.png?m=1413707431",
23 | // "avatar_normal" : "//cdn.v2ex.co/avatar/d165/7a2a/27619_normal.png?m=1413707431",
24 | // "avatar_large" : "//cdn.v2ex.co/avatar/d165/7a2a/27619_large.png?m=1413707431"
25 | // },
26 | // "created" : 1453030169,
27 | // "last_modified" : 1453030169
28 | // }
29 |
30 | @Parcelize
31 | data class Reply(var id: String = "",
32 | var content: String = "",
33 | var content_rendered: String = "",
34 | var thanks: Int = 0,
35 | var created: Long = 0,
36 | var createdOriginal: String= "",
37 | var isThanked: Boolean = false,
38 | var member: Member? = null,
39 | var isLouzu: Boolean = false,
40 | var showTime: String = "",
41 | private var rowNum: Int = -1,
42 | ) : Parcelable {
43 |
44 | fun setRowNum(num: Int) {
45 | rowNum = num
46 | }
47 | fun getRowNum(base:Int = 0) : Int = if (rowNum <= 0) base else rowNum
48 |
49 | override fun toString() = "Reply{content='$content_rendered}"
50 | }
51 |
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/utils/EndlessOnScrollListener.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.utils
2 |
3 | import androidx.recyclerview.widget.LinearLayoutManager
4 | import androidx.recyclerview.widget.RecyclerView
5 | import com.elvishew.xlog.XLog
6 | import im.fdx.v2ex.utils.extensions.logd
7 |
8 | abstract class EndlessOnScrollListener(val rvReply: RecyclerView, val mLinearLayoutManager:LinearLayoutManager) : RecyclerView.OnScrollListener() {
9 |
10 | private val visibleThreshold = 2
11 |
12 | private var pageToLoad = 1
13 |
14 | var loading = false
15 | var totalPage = 0
16 |
17 | private var pageAfterLoaded = pageToLoad
18 |
19 | override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
20 | XLog.d("onScrolled + $dy")
21 | if (dy <= 0) {
22 | return
23 | }
24 | val visibleItemCount = recyclerView.childCount
25 | val totalItemCount = mLinearLayoutManager.itemCount
26 | val firstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition()
27 | val lastVisibleItem = mLinearLayoutManager.findLastCompletelyVisibleItemPosition()
28 |
29 | synchronized(this) {
30 |
31 | logd("$totalItemCount , $lastVisibleItem , $pageToLoad")
32 | if (lastVisibleItem == totalItemCount - 1) {
33 | rvReply.stopScroll()
34 | if (pageAfterLoaded == totalPage) {
35 | onCompleted()
36 | }
37 | }
38 |
39 | if (pageToLoad < totalPage && !loading && totalItemCount - visibleItemCount <= firstVisibleItem + visibleThreshold) {
40 | // End has been reached, Do something
41 | pageToLoad++
42 | onLoadMore(pageToLoad)
43 | loading = true
44 | }
45 | }
46 | }
47 |
48 | fun restart() {
49 | pageToLoad = 1
50 | }
51 |
52 | fun isRestart() :Boolean {
53 | return pageToLoad == 1
54 | }
55 |
56 | fun success() {
57 | pageAfterLoaded = pageToLoad
58 | }
59 |
60 | abstract fun onLoadMore(currentPage: Int)
61 | abstract fun onCompleted()
62 |
63 | }
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/utils/ViewUtil.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.utils
2 |
3 | import android.content.res.Resources
4 |
5 |
6 | /**
7 | * Created by fdx on 2017/4/29.
8 | *
9 | *
10 | * pixel 和 dp 转换
11 | */
12 |
13 | object ViewUtil {
14 | val screenHeight: Int
15 | get() {
16 | val metrics = Resources.getSystem().displayMetrics
17 |
18 | return metrics.heightPixels
19 | }
20 |
21 | val screenWidth : Int
22 | get() {
23 |
24 | return Resources.getSystem().displayMetrics.widthPixels
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/utils/extensions/DpExt.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.utils.extensions
2 |
3 | import android.content.res.Resources
4 | import kotlin.math.roundToInt
5 |
6 |
7 | /**
8 | * Created by fdx on 2017/6/8.
9 | * fdx will maintain it
10 | */
11 |
12 |
13 | fun Int.dp2px(): Int {
14 | val metrics = Resources.getSystem().displayMetrics
15 | val px = this * 1.0f * (metrics.densityDpi / 160f)
16 | return px.roundToInt()
17 | }
18 |
19 | fun Int.px2dp(): Int {
20 | val metrics = Resources.getSystem().displayMetrics
21 | val dp = this * 1.0f / (metrics.densityDpi / 160f)
22 | return dp.roundToInt()
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/utils/extensions/StringExt.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.utils.extensions
2 |
3 | import java.net.URLDecoder
4 |
5 | /**
6 | * Created by fdx on 2017/7/3.
7 | * fdx will maintain it
8 | */
9 |
10 |
11 | /**
12 | * 将链接转成完整链接,一般用 GoodTextView
13 | */
14 | fun String.fullUrl() = this.replace("href=\"/member/", "href=\"https://www.v2ex.com/member/")
15 | .replace("href=\"/i/", "href=\"https://i.v2ex.co/")
16 | .replace("href=\"/t/", "href=\"https://www.v2ex.com/t/")
17 | .replace("href=\"/go/", "href=\"https://www.v2ex.com/go/")
18 | .replace("
Unit): BottomSheetMenu {
43 | val view = LayoutInflater.from(activity).inflate(R.layout.simple_list_item_center, null, false) as TextView
44 | view.text = title
45 | view.setOnClickListener{
46 | action()
47 | bottomSheet.dismiss()
48 | }
49 | val p = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
50 | container.addView(view, p)
51 | return this
52 | }
53 |
54 | fun addDivider() : BottomSheetMenu {
55 | val view = View(activity)
56 | view.layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, 1)
57 | view.setPadding(0, 6, 0, 6)
58 | view.setBackgroundColor(ContextCompat.getColor(activity, R.color.divider_color))
59 | container.addView(view)
60 | return this
61 | }
62 |
63 | fun addItems(titles: List, action: (Int,String) -> Unit): BottomSheetMenu {
64 | titles.forEachIndexed { index, s ->
65 | addItem(s) {
66 | action(index, s)
67 | }
68 | }
69 | return this
70 | }
71 |
72 |
73 | fun show() {
74 | if(!activity.isDestroyed) {
75 | bottomSheet.show()
76 | }
77 | }
78 | }
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/view/CustomChrome.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.view
2 |
3 | import android.content.ActivityNotFoundException
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.net.Uri
7 | import androidx.browser.customtabs.CustomTabColorSchemeParams
8 | import androidx.browser.customtabs.CustomTabsIntent
9 | import androidx.core.content.ContextCompat
10 | import androidx.core.content.ContextCompat.startActivity
11 | import im.fdx.v2ex.R
12 |
13 |
14 | /**
15 | * Created by fdx on 2017/3/23.
16 | * 无法设置文字颜色
17 | */
18 | class CustomChrome(private val context: Context) {
19 | private val builder: CustomTabsIntent.Builder = CustomTabsIntent.Builder()
20 |
21 | init {
22 | builder.setShowTitle(true)
23 | builder.setDefaultColorSchemeParams(
24 | CustomTabColorSchemeParams.Builder()
25 | .setToolbarColor(ContextCompat.getColor(context, R.color.chrome_tab)).build()
26 | )
27 | builder.setShareState(CustomTabsIntent.SHARE_STATE_ON)
28 | }
29 |
30 | fun load(url: String) {
31 |
32 | val customTabsIntent = builder.build()
33 | try {
34 | customTabsIntent.launchUrl(context, Uri.parse(url))
35 | } catch (e: ActivityNotFoundException) {
36 | val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
37 | context.startActivity(intent)
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/view/NaviItem.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.view
2 |
3 | import android.content.Context
4 | import android.graphics.drawable.Drawable
5 | import android.util.AttributeSet
6 | import android.widget.FrameLayout
7 | import android.widget.ImageView
8 | import android.widget.TextView
9 | import im.fdx.v2ex.R
10 |
11 | /**
12 | * TODO: document your custom view class.
13 | */
14 | class NaviItem : FrameLayout {
15 | /**
16 | * In the example view, this drawable is drawn above the text.
17 | */
18 | var exampleDrawable: Drawable? = null
19 |
20 | constructor(context: Context) : super(context) {
21 | init(null, 0)
22 | }
23 |
24 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
25 | init(attrs, 0)
26 | }
27 |
28 | constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(
29 | context,
30 | attrs,
31 | defStyle
32 | ) {
33 | init(attrs, defStyle)
34 | }
35 |
36 | var icon: Drawable? = null
37 | var title: String? = null
38 |
39 | private fun init(attrs: AttributeSet?, defStyle: Int) {
40 | // Load attributes
41 | val a = context.obtainStyledAttributes(
42 | attrs, R.styleable.NaviItem, defStyle, 0
43 | )
44 | title = a.getString(
45 | R.styleable.NaviItem_title
46 | )
47 | icon = a.getDrawable(R.styleable.NaviItem_icon)
48 | a.recycle()
49 | inflate(context, R.layout.navi_item, this)
50 |
51 | findViewById(R.id.title).text = title
52 | findViewById(R.id.icon).setImageDrawable(icon)
53 |
54 | }
55 | }
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/view/ViewPagerHelper.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.view
2 |
3 | import android.view.MotionEvent
4 | import androidx.viewpager2.widget.ViewPager2
5 | import kotlin.math.abs
6 |
7 | class ViewPagerHelper(val viewPager2: ViewPager2) {
8 |
9 | private var initialXValue = 0f
10 | private var initialYValue = 0f
11 | fun dispatchTouchEvent(ev: MotionEvent) {
12 | if (ev.action == MotionEvent.ACTION_DOWN) {
13 | initialXValue = ev.x
14 | initialYValue = ev.y
15 | }
16 | if (ev.action == MotionEvent.ACTION_MOVE) {
17 | val diffX: Float = ev.x - initialXValue
18 | val diffY: Float = ev.y - initialYValue
19 | if (abs(diffY) > 1.4 * abs(diffX)) {
20 | if (viewPager2.scrollState != ViewPager2.SCROLL_STATE_DRAGGING) {
21 | viewPager2.isUserInputEnabled = false
22 | }
23 | }
24 | }
25 | if (ev.action == MotionEvent.ACTION_UP) {
26 | initialXValue = 0f
27 | initialYValue = 0f
28 | viewPager2.isUserInputEnabled = true
29 | }
30 | }
31 |
32 |
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/im/fdx/v2ex/view/ZoomOutPageTransform.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.view
2 |
3 | import android.annotation.SuppressLint
4 | import android.util.Log
5 | import android.view.View
6 |
7 | import androidx.viewpager.widget.ViewPager
8 | import androidx.viewpager2.widget.ViewPager2
9 | import kotlin.math.abs
10 | import kotlin.math.max
11 |
12 | class ZoomOutPageTransform : ViewPager2.PageTransformer {
13 |
14 | @SuppressLint("NewApi")
15 | override fun transformPage(view: View, position: Float) {
16 | val pageWidth = view.width
17 | val pageHeight = view.height
18 |
19 | Log.e("TAG", "$view , $position")
20 |
21 | when {
22 | position < -1 -> // [-Infinity,-1)
23 | // This page is way off-screen to the left.
24 | view.alpha = 0f
25 | position <= 1
26 | //a页滑动至b页 ; a页从 0.0 -1 ;b页从1 ~ 0.0
27 | -> { // [-1,1]
28 | // Modify the default slide transition to shrink the page as well
29 | val scaleFactor = max(MIN_SCALE, 1 - abs(position))
30 | val vertMargin = pageHeight * (1 - scaleFactor) / 2
31 | val horzMargin = pageWidth * (1 - scaleFactor) / 2
32 | if (position < 0) {
33 | view.translationX = horzMargin - vertMargin / 2
34 | } else {
35 | view.translationX = -horzMargin + vertMargin / 2
36 | }
37 |
38 | // Scale the page down (between MIN_SCALE and 1)
39 | view.scaleX = scaleFactor
40 | view.scaleY = scaleFactor
41 |
42 | // Fade the page relative to its size.
43 | view.alpha = MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA)
44 |
45 | }
46 | else -> // (1,+Infinity]
47 | // This page is way off-screen to the right.
48 | view.alpha = 0f
49 | }
50 | }
51 |
52 | companion object {
53 | private const val MIN_SCALE = 0.95f
54 | private const val MIN_ALPHA = 1f
55 | }
56 | }
--------------------------------------------------------------------------------
/app/src/main/logo-alpha.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/logo-alpha.png
--------------------------------------------------------------------------------
/app/src/main/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/logo.png
--------------------------------------------------------------------------------
/app/src/main/res/anim/hide_toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/node_title_ctl.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/rotate_refresh.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/show_toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-night/ic_night_mode.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/bg_nav_header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/drawable-xxhdpi/bg_nav_header.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_shortcut_create.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/drawable-xxhdpi/ic_shortcut_create.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/loading_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/drawable-xxhdpi/loading_image.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/loading_image_4_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/drawable-xxhdpi/loading_image_4_3.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_arrow_drop_down_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_close_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_manage_search_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/border.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/border_page_num.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | -
8 |
9 |
10 |
13 |
14 |
15 |
16 | -
17 |
18 |
19 |
22 |
23 |
24 |
25 |
26 | -
27 |
28 |
29 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/divider.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_add_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_all_node.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_announcement_hint_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_arrow_back_primary_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_account_circle_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_add_circle_outline_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_arrow_downward_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_remove_circle_outline_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_report_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bitcoin.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_block_primary_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_block_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_check_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_circle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_comment.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_daily_check.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_dehaze_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_delete.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_edit_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_favorite_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_favorite_blue_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_favorite_border_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_favorite_border_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_favorite_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_github.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_location.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_message_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_night_mode.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_notification_with_red_point.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 | -
9 |
10 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_notifications_none_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_notifications_primary_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_notifications_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_person_outline_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_profile.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_refresh_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search_primary_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search_white_48px.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_send_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_send_hint_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_send_primary_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_send_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_settings_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_share_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_share_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_thank.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_thank_new.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_thumbs_up.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_twitter.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_website.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_zoom_out_map_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/loading.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/logo2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/drawable/logo2x.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/radius_2dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/radius_4dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/radius_8dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/radius_outline_4dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/radius_outline_4dp_primary.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/rounded_close_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/spinner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/themed_icon.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_all_nodes.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
19 |
20 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_base.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_details.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_follow_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
19 |
20 |
27 |
28 |
29 |
30 |
31 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main_content.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
17 |
18 |
27 |
28 |
31 |
32 |
33 |
34 |
35 |
36 |
42 |
43 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_notification.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_photo.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_settings.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_test.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_web_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/app_toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/appbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/bottom_list_sheet.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_et.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/divider.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_tab_article.xml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
18 |
19 |
26 |
27 |
31 |
32 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_all_nodes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
21 |
22 |
34 |
35 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_comments.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
20 |
21 |
33 |
34 |
49 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_load_more.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_node.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_node_simple.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_node_with_category.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
20 |
21 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_reply_member.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
27 |
28 |
40 |
41 |
51 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_text_switch.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
18 |
19 |
33 |
34 |
35 |
36 |
37 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_topic_with_comments.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
20 |
21 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/iv_refresh.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/navi_item.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
20 |
21 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/page_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/pager_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
14 |
25 |
26 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/popwindow_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/simple_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/simple_list_item_center.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/text_view_spinner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_page_number.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
18 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_activity_nav_drawer.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_all_node.xml:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_details.xml:
--------------------------------------------------------------------------------
1 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_member.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_node.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_reply.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_search.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_tab_setting.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_topic_fragement.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_notification_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/mipmap-hdpi/ic_notification_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_notification_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/mipmap-mdpi/ic_notification_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_notification_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/mipmap-xhdpi/ic_notification_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_notification_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/mipmap-xxhdpi/ic_notification_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_notification_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/app/src/main/res/mipmap-xxxhdpi/ic_notification_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/transition/change_image_transform.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/transition/explode.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #cccccc
7 | @color/white
8 | @color/white
9 | @color/white
10 | #cbcbcb
11 | #cbcbcb
12 |
13 | @color/transparent
14 | @color/white
15 |
16 |
17 | #0097A7
18 | @color/base_night
19 | @color/white
20 | @color/white
21 |
22 |
23 |
24 |
25 | #606060
26 | #A3A3A3
27 | #61000000
28 |
29 |
30 | @color/white
31 | @color/white
32 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs_navi_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs_page_number_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 1dp
3 | 1dp
4 | 48dp
5 | 16dp
6 |
7 | 16dp
8 | 14sp
9 | 16dp
10 | 16dp
11 | 160dp
12 | 6dp
13 | 8dp
14 | 16dp
15 |
16 |
17 | 16sp
18 | 14sp
19 | 12sp
20 |
21 | 18sp
22 | 16sp
23 | 14sp
24 |
25 | 20sp
26 | 18sp
27 | 16sp
28 |
29 | 22sp
30 | 20sp
31 | 18sp
32 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/xml-v25/shortcuts.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 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_descriptor.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/preference.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
18 |
19 |
25 |
26 |
29 |
30 |
38 |
39 |
47 |
48 |
49 |
50 |
51 |
54 |
55 |
58 |
59 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/preference_login.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
10 |
16 |
17 |
23 |
24 |
25 |
26 |
30 |
36 |
42 |
49 |
50 |
51 |
55 |
56 |
59 |
60 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/provider_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/remote_config_defaults.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | google_sign_in_url
5 | https://www.v2ex.com/signin
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/searchable.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/app/src/testDebug/java/im/fdx/v2ex/network/HttpHelperTest.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.network
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | * Created by fdx on 2016/11/20.
7 | * fdx will maintain it
8 | */
9 | class HttpHelperTest {
10 | @Test
11 | @Throws(Exception::class)
12 | fun doSomething() {
13 |
14 | // new HttpHelper().doSomething();
15 | }
16 |
17 | }
--------------------------------------------------------------------------------
/app/src/testDebug/java/im/fdx/v2ex/network/JsonManagerTest.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.network
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | * Created by fdx on 2016/11/19.
7 | * fdx will maintain it
8 | */
9 | class JsonManagerTest {
10 | @Test
11 | @Throws(Exception::class)
12 | fun getOnceCode() {
13 |
14 | }
15 |
16 | }
--------------------------------------------------------------------------------
/app/src/testDebug/java/im/fdx/v2ex/utils/ContentUtilsTest.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.utils
2 |
3 | import im.fdx.v2ex.utils.extensions.fullUrl
4 | import org.junit.Assert.assertEquals
5 | import org.junit.Test
6 |
7 | /**
8 | * Created by fdx on 2016/9/11.
9 | * fdx will maintain it
10 | */
11 | class ContentUtilsTest {
12 | @Test
13 | @Throws(Exception::class)
14 | fun formatContent() {
15 | val s = "href=\"/go/"
16 | val out = s.fullUrl()
17 |
18 |
19 | assertEquals(out, "href=\"https://www.v2ex.com/go/")
20 | }
21 |
22 |
23 | @Test
24 | @Throws(Exception::class)
25 | fun TimeFormat() {
26 | val s = TimeUtil.getAbsoluteTime("1341262360")
27 | assertEquals("succeed", "2012/07/03", s)
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/testDebug/java/im/fdx/v2ex/utils/SecureUtilsTest.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.utils
2 |
3 | import android.os.Build
4 | import androidx.annotation.RequiresApi
5 | import org.junit.Test
6 |
7 | /**
8 | * Created by fdx on 2017/3/17.
9 | */
10 | class SecureUtilsTest {
11 |
12 | // public SecureUtils utils = new SecureUtils();
13 |
14 | //需要mock才能进行,失败
15 | @RequiresApi(api = Build.VERSION_CODES.M)
16 | @Test
17 | @Throws(Exception::class)
18 | fun encrypt() {
19 | // SecureUtils utils = new SecureUtils();
20 | // String encrypt = utils.encrypt("what the fuck");
21 | // String decrypt = utils.decrypt(encrypt);
22 | // assertEquals("what the fuck", decrypt);
23 | }
24 |
25 | @Test
26 | @Throws(Exception::class)
27 | fun decrypt() {
28 |
29 | }
30 |
31 | }
--------------------------------------------------------------------------------
/app/src/testDebug/java/im/fdx/v2ex/utils/StringTest.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.utils
2 |
3 | import org.junit.Assert
4 | import org.junit.Test
5 |
6 | /**
7 | * Created by fdx on 2017/10/9.
8 | *
9 | */
10 | class StringTest {
11 | @Test
12 | fun test() {
13 | Assert.assertEquals("android".contains("abcd"), false)
14 | Assert.assertEquals("android".contains("anc"), false)
15 | Assert.assertEquals("android".contains("and"), true)
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/testDebug/java/im/fdx/v2ex/utils/TimeUtilTest.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.utils
2 |
3 | import org.junit.Test
4 | import java.text.SimpleDateFormat
5 | import java.util.*
6 |
7 | @Suppress("UNUSED_VARIABLE")
8 | /**
9 | * Created by fdx on 2017/7/16.
10 | * fdx will maintain it
11 | */
12 | class TimeUtilTest {
13 | @Test
14 | fun toLong() {
15 |
16 | val ccc = SimpleDateFormat("yyyy-MM-dd hh:mm:ss a", Locale.US)
17 | val date = ccc.parse("2014-08-08 08:56:06 AM")
18 | }
19 |
20 | }
--------------------------------------------------------------------------------
/app/src/testDebug/java/im/fdx/v2ex/utils/extensions/StringExtKtTest.kt:
--------------------------------------------------------------------------------
1 | package im.fdx.v2ex.utils.extensions
2 |
3 | import org.junit.Assert.assertEquals
4 | import org.junit.Test
5 |
6 | /**
7 | * Created by fdx on 2017/7/15.
8 | * fdx will maintain it
9 | */
10 | class StringExtKtTest {
11 | @Test
12 | fun getPair() {
13 | val row = " @fdx #23".findRownum("fdx")
14 |
15 | val row2 = "@fdx sjfksd".findRownum("fdx")
16 | val row3 = "abcdefsdf".findRownum("fdx")
17 |
18 | val row4 = "@fdx sdssds, @ccc #123 , bac \n @3224 #345".findRownum("3224")
19 | assertEquals(row, 23)
20 | assertEquals(row2, -1)
21 | assertEquals(row3, -1)
22 | assertEquals(row4, 345)
23 |
24 | }
25 |
26 | }
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 |
4 | buildscript {
5 | extra["kotlinVersion"] = "1.9.10"
6 | dependencies {
7 | classpath("com.android.tools.build:gradle:8.1.2")
8 | classpath("com.google.gms:google-services:4.4.0")
9 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${project.extra["kotlinVersion"]}")
10 | classpath("com.google.firebase:firebase-crashlytics-gradle:2.9.9")
11 | classpath ("com.google.firebase:perf-plugin:1.4.2")
12 | }
13 | }
14 | plugins {
15 | id("com.google.devtools.ksp") version "1.9.10-1.0.13" apply false
16 | }
--------------------------------------------------------------------------------
/fastlane/Appfile:
--------------------------------------------------------------------------------
1 | json_key_file("C:\\f_code\\key\\pc-api.json") # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one
2 | package_name("im.fdx.v2ex") # e.g. com.krausefx.app
3 |
--------------------------------------------------------------------------------
/fastlane/Fastfile:
--------------------------------------------------------------------------------
1 | # This file contains the fastlane.tools configuration
2 | # You can find the documentation at https://docs.fastlane.tools
3 | #
4 | # For a list of all available actions, check out
5 | #
6 | # https://docs.fastlane.tools/actions
7 | #
8 | # For a list of all available plugins, check out
9 | #
10 | # https://docs.fastlane.tools/plugins/available-plugins
11 | #
12 |
13 | # Uncomment the line if you want fastlane to automatically update itself
14 | # update_fastlane
15 |
16 | default_platform(:android)
17 |
18 | platform :android do
19 | desc "Runs all the tests"
20 | lane :test do
21 | gradle(task: "test")
22 | end
23 |
24 | desc "Submit a new Beta Build to Crashlytics Beta"
25 | lane :beta do
26 | gradle(task: "clean assembleRelease")
27 | crashlytics
28 |
29 | # sh "your_script.sh"
30 | # You can also use other beta testing services here
31 | end
32 |
33 | desc "(bundle)Deploy a internal version to the Google Play"
34 | lane :internal do
35 | gradle(task: "clean bundleRelease")
36 | upload_to_play_store(track: 'internal',
37 | skip_upload_metadata: true,
38 | skip_upload_screenshots: true,
39 | skip_upload_images: true,
40 | )
41 | end
42 |
43 | desc "(bundle)Deploy a new version to production the Google Play"
44 | lane :prod do
45 | gradle(task: "clean bundleRelease")
46 | upload_to_play_store(track: 'production',
47 | skip_upload_metadata: true,
48 | skip_upload_screenshots: true,
49 | skip_upload_images: true,
50 | skip_upload_apk: true,
51 | )
52 | end
53 |
54 | desc "promote to production"
55 | lane :promote do
56 | upload_to_play_store(track: 'internal',
57 | track_promote_to: 'production',
58 | track_promote_release_status: 'completed',
59 | version_code: ,
60 | skip_upload_metadata: true,
61 | skip_upload_screenshots: true,
62 | skip_upload_images: true,
63 | skip_upload_changelogs: true
64 | )
65 | end
66 |
67 | desc "Build debug and test APK for screenshots"
68 | lane :build_for_screengrab do
69 | gradle(
70 | task: 'clean'
71 | )
72 | build_android_app(
73 | task: 'assemble',
74 | build_type: 'Debug'
75 | )
76 | build_android_app(
77 | task: 'assemble',
78 | build_type: 'AndroidTest'
79 | )
80 | end
81 | end
82 |
--------------------------------------------------------------------------------
/fastlane/README.md:
--------------------------------------------------------------------------------
1 | fastlane documentation
2 | ----
3 |
4 | # Installation
5 |
6 | Make sure you have the latest version of the Xcode command line tools installed:
7 |
8 | ```sh
9 | xcode-select --install
10 | ```
11 |
12 | For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane)
13 |
14 | # Available Actions
15 |
16 | ## Android
17 |
18 | ### android test
19 |
20 | ```sh
21 | [bundle exec] fastlane android test
22 | ```
23 |
24 | Runs all the tests
25 |
26 | ### android beta
27 |
28 | ```sh
29 | [bundle exec] fastlane android beta
30 | ```
31 |
32 | Submit a new Beta Build to Crashlytics Beta
33 |
34 | ### android internal
35 |
36 | ```sh
37 | [bundle exec] fastlane android internal
38 | ```
39 |
40 | (bundle)Deploy a internal version to the Google Play
41 |
42 | ### android prod
43 |
44 | ```sh
45 | [bundle exec] fastlane android prod
46 | ```
47 |
48 | (bundle)Deploy a new version to production the Google Play
49 |
50 | ### android promote
51 |
52 | ```sh
53 | [bundle exec] fastlane android promote
54 | ```
55 |
56 | promote to production
57 |
58 | ### android build_for_screengrab
59 |
60 | ```sh
61 | [bundle exec] fastlane android build_for_screengrab
62 | ```
63 |
64 | Build debug and test APK for screenshots
65 |
66 | ----
67 |
68 | This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run.
69 |
70 | More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools).
71 |
72 | The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
73 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/zh-CN/changelogs/61.txt:
--------------------------------------------------------------------------------
1 | * 修复“收藏关注”里网络错误问题
--------------------------------------------------------------------------------
/fastlane/metadata/android/zh-CN/changelogs/62.txt:
--------------------------------------------------------------------------------
1 | * 优化用户页面的显示,增加回复总数和主题总数
2 | * 加入全局设置,是否"用户页面"和"我的收藏页面"显示页码
--------------------------------------------------------------------------------
/fastlane/metadata/android/zh-CN/changelogs/66.txt:
--------------------------------------------------------------------------------
1 | * 修复可能存在的Google 登录失败的问题
2 | * 增加一些搜索的选项
--------------------------------------------------------------------------------
/fastlane/metadata/android/zh-CN/changelogs/69.txt:
--------------------------------------------------------------------------------
1 | * 修复水深火热节点异常
--------------------------------------------------------------------------------
/fastlane/metadata/android/zh-CN/changelogs/default.txt:
--------------------------------------------------------------------------------
1 | * 问题修复和性能优化
--------------------------------------------------------------------------------
/fastlane/metadata/android/zh-CN/full_description.txt:
--------------------------------------------------------------------------------
1 | 主要功能有:
2 | * 使用V2EX的大部分功能,包括浏览主题、发表文章、评论,点赞等
3 | * 个性化设置,包括字体大小,深色主题等
4 |
5 | Github开源地址 https://github.com/fan123199/v2ex-simple
--------------------------------------------------------------------------------
/fastlane/metadata/android/zh-CN/images/featureGraphic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/fastlane/metadata/android/zh-CN/images/featureGraphic.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/zh-CN/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/fastlane/metadata/android/zh-CN/images/icon.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/zh-CN/images/phoneScreenshots/1_zh-CN.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/fastlane/metadata/android/zh-CN/images/phoneScreenshots/1_zh-CN.jpeg
--------------------------------------------------------------------------------
/fastlane/metadata/android/zh-CN/images/phoneScreenshots/2_zh-CN.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/fastlane/metadata/android/zh-CN/images/phoneScreenshots/2_zh-CN.jpeg
--------------------------------------------------------------------------------
/fastlane/metadata/android/zh-CN/images/phoneScreenshots/3_zh-CN.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/fastlane/metadata/android/zh-CN/images/phoneScreenshots/3_zh-CN.jpeg
--------------------------------------------------------------------------------
/fastlane/metadata/android/zh-CN/images/phoneScreenshots/4_zh-CN.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/fastlane/metadata/android/zh-CN/images/phoneScreenshots/4_zh-CN.jpeg
--------------------------------------------------------------------------------
/fastlane/metadata/android/zh-CN/images/phoneScreenshots/5_zh-CN.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/fastlane/metadata/android/zh-CN/images/phoneScreenshots/5_zh-CN.jpeg
--------------------------------------------------------------------------------
/fastlane/metadata/android/zh-CN/short_description.txt:
--------------------------------------------------------------------------------
1 | V2EX第三方客户端,简洁且功能齐全
--------------------------------------------------------------------------------
/fastlane/metadata/android/zh-CN/title.txt:
--------------------------------------------------------------------------------
1 | 探索路V2EX
--------------------------------------------------------------------------------
/fastlane/metadata/android/zh-CN/video.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/fastlane/metadata/android/zh-CN/video.txt
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | ## Project-wide Gradle settings.
2 | #
3 | # For more details on how to configure your build environment visit
4 | # http://www.gradle.org/docs/current/userguide/build_environment.html
5 | #
6 | # Specifies the JVM arguments used for the daemon process.
7 | # The setting is particularly useful for tweaking memory settings.
8 | # Default value: -Xmx1024m -XX:MaxPermSize=256m
9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
10 | #
11 | # When configured, Gradle will run in incubating parallel mode.
12 | # This option should only be used with decoupled projects. More details, visit
13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
14 | # org.gradle.parallel=true
15 | #Thu Aug 10 09:10:35 CST 2017
16 | #systemProp.http.proxyHost=127.0.0.1
17 | #systemProp.http.proxyPort=2080
18 | #systemProp.https.nonProxyHosts=dl.google.com
19 | #systemProp.https.proxyHost=127.0.0.1
20 | #systemProp.https.proxyPort=2080
21 | #systemProp.http.nonProxyHosts=dl.google.com
22 | android.defaults.buildfeatures.buildconfig=true
23 | android.enableJetifier=true
24 | android.nonFinalResIds=false
25 | android.nonTransitiveRClass=false
26 | android.useAndroidX=true
27 | org.gradle.jvmargs=-Xmx2048m
28 | #android.debug.obsoleteApi=true
29 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Aug 21 21:45:50 CST 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip
7 |
--------------------------------------------------------------------------------
/privacy.md:
--------------------------------------------------------------------------------
1 | # Privacy
2 |
3 | ## Why App have Camera permission?
4 |
5 | A: we use it to take photo to post a topic. It is easy to add photo to a topic.
--------------------------------------------------------------------------------
/searchablespinnerlibrary/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | *.iml
--------------------------------------------------------------------------------
/searchablespinnerlibrary/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 27
5 | buildToolsVersion '27.0.3'
6 |
7 | defaultConfig {
8 | minSdkVersion 15
9 | targetSdkVersion 27
10 | versionCode 8
11 | versionName "1.3.1"
12 | }
13 | buildTypes {
14 | }
15 | }
16 | dependencies {
17 | }
--------------------------------------------------------------------------------
/searchablespinnerlibrary/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/Meditab/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/searchablespinnerlibrary/src/androidTest/java/com/toptoche/searchablespinnerlibrary/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.toptoche.searchablespinnerlibrary;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/searchablespinnerlibrary/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/searchablespinnerlibrary/src/main/res/layout/searchable_list_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
17 |
18 |
22 |
23 |
--------------------------------------------------------------------------------
/searchablespinnerlibrary/src/main/res/nobleltevzwLMY47XMeditab02192016201518.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fan123199/v2ex-simple/c0778b6aae99b19567671fd5fc858ea007f26820/searchablespinnerlibrary/src/main/res/nobleltevzwLMY47XMeditab02192016201518.gif
--------------------------------------------------------------------------------
/searchablespinnerlibrary/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/searchablespinnerlibrary/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SearchableSpinnerLibrary
3 |
4 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | gradlePluginPortal()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | maven { url = uri("https://jitpack.io") }
14 | }
15 | }
16 | rootProject.name = "v2ex-simple"
17 |
18 |
19 | include(":app")
--------------------------------------------------------------------------------