├── .watchmanconfig ├── res ├── images │ ├── ic_my.png │ ├── logo.png │ ├── ic_code.png │ ├── ic_line.png │ ├── ic_my@2x.png │ ├── ic_my@3x.png │ ├── ic_pages.png │ ├── ic_share.png │ ├── ic_star.png │ ├── ic_code@2x.png │ ├── ic_code@3x.png │ ├── ic_polular.png │ ├── ic_star@2x.png │ ├── ic_star@3x.png │ ├── ic_unstar.png │ ├── ic_computer.png │ ├── ic_contacts.png │ ├── ic_favorite.png │ ├── ic_feedback.png │ ├── ic_pages@2x.png │ ├── ic_pages@3x.png │ ├── ic_polular@2x.png │ ├── ic_polular@3x.png │ ├── ic_share@2x.png │ ├── ic_share@3x.png │ ├── ic_tiaozhuan.png │ ├── ic_trending.png │ ├── ic_unstar@2x.png │ ├── ic_unstar@3x.png │ ├── ic_computer@2x.png │ ├── ic_computer@3x.png │ ├── ic_contacts@2x.png │ ├── ic_contacts@3x.png │ ├── ic_favorite@2x.png │ ├── ic_favorite@3x.png │ ├── ic_feedback@2x.png │ ├── ic_feedback@3x.png │ ├── ic_star_navbar.png │ ├── ic_tiaozhuan@2x.png │ ├── ic_tiaozhuan@3x.png │ ├── ic_tiaozhuan_up.png │ ├── ic_trending@2x.png │ ├── ic_trending@3x.png │ ├── ic_star_navbar@2x.png │ ├── ic_star_navbar@3x.png │ ├── ic_tiaozhuan_down.png │ ├── ic_tiaozhuan_up@2x.png │ ├── ic_tiaozhuan_up@3x.png │ ├── ic_unstar_navbar.png │ ├── ic_remove_white@36pt.png │ ├── ic_search_white_48pt.png │ ├── ic_spinner_triangle.png │ ├── ic_tiaozhuan_down@2x.png │ ├── ic_tiaozhuan_down@3x.png │ ├── ic_unstar_navbar@2x.png │ ├── ic_unstar_navbar@3x.png │ ├── ic_more_vert_white_48pt.png │ ├── ic_remove_white_36pt@2x.png │ ├── ic_remove_white_36pt@3x.png │ ├── ic_search_white_48pt@2x.png │ ├── ic_search_white_48pt@3x.png │ ├── ic_unstar_transparent.png │ ├── ic_arrow_back_white_36pt.png │ ├── ic_star_border_white_24dp.png │ ├── ic_unstar_transparent@2x.png │ ├── ic_unstar_transparent@3x.png │ ├── ic_arrow_back_white_36pt@2x.png │ ├── ic_arrow_back_white_36pt@3x.png │ ├── ic_more_vert_white_48pt@2x.png │ └── ic_more_vert_white_48pt@3x.png ├── data │ ├── keys.json │ ├── Config.json │ └── langs.json └── styles │ ├── GlobalStyles.js │ └── ThemeFactory.js ├── js ├── page │ ├── my │ │ ├── img │ │ │ ├── ic_add.png │ │ │ ├── ic_add@2x.png │ │ │ ├── ic_add@3x.png │ │ │ ├── ic_remove.png │ │ │ ├── ic_sort.png │ │ │ ├── ic_sort@2x.png │ │ │ ├── ic_sort@3x.png │ │ │ ├── ic_brightness.png │ │ │ ├── ic_check_box.png │ │ │ ├── ic_remove@2x.png │ │ │ ├── ic_remove@3x.png │ │ │ ├── ic_swap_vert.png │ │ │ ├── ic_view_quilt.png │ │ │ ├── ic_brightness@2x.png │ │ │ ├── ic_brightness@3x.png │ │ │ ├── ic_check_box@2x.png │ │ │ ├── ic_check_box@3x.png │ │ │ ├── ic_custom_theme.png │ │ │ ├── ic_swap_vert@2x.png │ │ │ ├── ic_swap_vert@3x.png │ │ │ ├── ic_view_quilt@2x.png │ │ │ ├── ic_view_quilt@3x.png │ │ │ ├── ic_custom_language.png │ │ │ ├── ic_custom_theme@2x.png │ │ │ ├── ic_custom_theme@3x.png │ │ │ ├── ic_insert_emoticon.png │ │ │ ├── ic_custom_language2x.png │ │ │ ├── ic_custom_language3x.png │ │ │ ├── ic_insert_emoticon@2x.png │ │ │ ├── ic_insert_emoticon@3x.png │ │ │ ├── ic_check_box_outline_blank.png │ │ │ ├── ic_check_box_outline_blank@2x.png │ │ │ └── ic_check_box_outline_blank@3x.png │ │ ├── CustomTheme.js │ │ ├── CustomKeyPage.js │ │ ├── SortKeyPagePage.js │ │ └── MyPage.js │ ├── setup.js │ ├── WelcomePage.js │ ├── WebViewPage.js │ ├── about │ │ ├── AboutPage.js │ │ ├── AboutCommon.js │ │ └── AboutMePage.js │ ├── RepositoryDetail.js │ ├── HomePage.js │ └── FavoritePage.js ├── model │ ├── TimeSpan.js │ └── ProjectModel.js ├── util │ ├── Utils.js │ ├── Cancelable.js │ ├── ArrayUtils.js │ └── ViewUtils.js ├── common │ ├── BaseCommon.js │ ├── MPColors.js │ ├── MenuItem.js │ ├── TrendingRepoCell.js │ ├── MoreMenu.js │ ├── RepositoryCell.js │ └── NavigationBar.js └── expand │ └── dao │ ├── ThemeDao.js │ ├── LanguageDao.js │ ├── RepositoryDao.js │ ├── FavoriteDao.js │ ├── DataRepository.js │ └── RepositoryUtils.js ├── resource ├── React-Native+Redux.jpg └── screenshot │ ├── GitHubPopular-1.jpg │ ├── GitHubPopular-2.jpg │ └── GitHubPopular-3.jpg ├── ios ├── GitHubPopular │ ├── Images.xcassets │ │ ├── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── 120.png │ │ │ ├── 180.png │ │ │ └── Contents.json │ │ └── LaunchImage.launchimage │ │ │ ├── LaunchScreen1242x2208.png │ │ │ ├── LaunchScreen640x960-1.png │ │ │ ├── LaunchScreen640x960.png │ │ │ ├── LaunchScreen750x1334.png │ │ │ ├── LaunchScreen640 × 1136.png │ │ │ ├── LaunchScreen640 × 1136-1.png │ │ │ └── Contents.json │ ├── AppDelegate.h │ ├── main.m │ ├── Info.plist │ ├── AppDelegate.m │ └── Base.lproj │ │ └── LaunchScreen.xib ├── GitHubPopularTests │ ├── Info.plist │ └── GitHubPopularTests.m └── GitHubPopular.xcodeproj │ └── xcshareddata │ └── xcschemes │ └── GitHubPopular.xcscheme ├── android ├── app │ ├── src │ │ └── main │ │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── drawable-xhdpi │ │ │ │ └── launch_screen.png │ │ │ ├── drawable-xxhdpi │ │ │ │ └── launch_screen.png │ │ │ └── layout │ │ │ │ └── launch_screen.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── jph │ │ │ │ └── githubpopular │ │ │ │ ├── MainActivity.java │ │ │ │ └── MainApplication.java │ │ │ └── AndroidManifest.xml │ ├── BUCK │ ├── proguard-rules.pro │ └── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── keystores │ ├── debug.keystore.properties │ └── BUCK ├── settings.gradle ├── build.gradle ├── gradle.properties ├── gradlew.bat └── gradlew ├── .buckconfig ├── index.android.js ├── index.ios.js ├── API.md ├── .gitignore ├── .tags1 ├── package.json ├── README.md ├── README.en.md └── .flowconfig /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /res/images/ic_my.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_my.png -------------------------------------------------------------------------------- /res/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/logo.png -------------------------------------------------------------------------------- /res/images/ic_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_code.png -------------------------------------------------------------------------------- /res/images/ic_line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_line.png -------------------------------------------------------------------------------- /res/images/ic_my@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_my@2x.png -------------------------------------------------------------------------------- /res/images/ic_my@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_my@3x.png -------------------------------------------------------------------------------- /res/images/ic_pages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_pages.png -------------------------------------------------------------------------------- /res/images/ic_share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_share.png -------------------------------------------------------------------------------- /res/images/ic_star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_star.png -------------------------------------------------------------------------------- /js/page/my/img/ic_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_add.png -------------------------------------------------------------------------------- /res/images/ic_code@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_code@2x.png -------------------------------------------------------------------------------- /res/images/ic_code@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_code@3x.png -------------------------------------------------------------------------------- /res/images/ic_polular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_polular.png -------------------------------------------------------------------------------- /res/images/ic_star@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_star@2x.png -------------------------------------------------------------------------------- /res/images/ic_star@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_star@3x.png -------------------------------------------------------------------------------- /res/images/ic_unstar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_unstar.png -------------------------------------------------------------------------------- /js/page/my/img/ic_add@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_add@2x.png -------------------------------------------------------------------------------- /js/page/my/img/ic_add@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_add@3x.png -------------------------------------------------------------------------------- /js/page/my/img/ic_remove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_remove.png -------------------------------------------------------------------------------- /js/page/my/img/ic_sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_sort.png -------------------------------------------------------------------------------- /res/images/ic_computer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_computer.png -------------------------------------------------------------------------------- /res/images/ic_contacts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_contacts.png -------------------------------------------------------------------------------- /res/images/ic_favorite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_favorite.png -------------------------------------------------------------------------------- /res/images/ic_feedback.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_feedback.png -------------------------------------------------------------------------------- /res/images/ic_pages@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_pages@2x.png -------------------------------------------------------------------------------- /res/images/ic_pages@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_pages@3x.png -------------------------------------------------------------------------------- /res/images/ic_polular@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_polular@2x.png -------------------------------------------------------------------------------- /res/images/ic_polular@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_polular@3x.png -------------------------------------------------------------------------------- /res/images/ic_share@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_share@2x.png -------------------------------------------------------------------------------- /res/images/ic_share@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_share@3x.png -------------------------------------------------------------------------------- /res/images/ic_tiaozhuan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_tiaozhuan.png -------------------------------------------------------------------------------- /res/images/ic_trending.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_trending.png -------------------------------------------------------------------------------- /res/images/ic_unstar@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_unstar@2x.png -------------------------------------------------------------------------------- /res/images/ic_unstar@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_unstar@3x.png -------------------------------------------------------------------------------- /js/page/my/img/ic_sort@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_sort@2x.png -------------------------------------------------------------------------------- /js/page/my/img/ic_sort@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_sort@3x.png -------------------------------------------------------------------------------- /res/images/ic_computer@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_computer@2x.png -------------------------------------------------------------------------------- /res/images/ic_computer@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_computer@3x.png -------------------------------------------------------------------------------- /res/images/ic_contacts@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_contacts@2x.png -------------------------------------------------------------------------------- /res/images/ic_contacts@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_contacts@3x.png -------------------------------------------------------------------------------- /res/images/ic_favorite@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_favorite@2x.png -------------------------------------------------------------------------------- /res/images/ic_favorite@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_favorite@3x.png -------------------------------------------------------------------------------- /res/images/ic_feedback@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_feedback@2x.png -------------------------------------------------------------------------------- /res/images/ic_feedback@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_feedback@3x.png -------------------------------------------------------------------------------- /res/images/ic_star_navbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_star_navbar.png -------------------------------------------------------------------------------- /res/images/ic_tiaozhuan@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_tiaozhuan@2x.png -------------------------------------------------------------------------------- /res/images/ic_tiaozhuan@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_tiaozhuan@3x.png -------------------------------------------------------------------------------- /res/images/ic_tiaozhuan_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_tiaozhuan_up.png -------------------------------------------------------------------------------- /res/images/ic_trending@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_trending@2x.png -------------------------------------------------------------------------------- /res/images/ic_trending@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_trending@3x.png -------------------------------------------------------------------------------- /js/page/my/img/ic_brightness.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_brightness.png -------------------------------------------------------------------------------- /js/page/my/img/ic_check_box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_check_box.png -------------------------------------------------------------------------------- /js/page/my/img/ic_remove@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_remove@2x.png -------------------------------------------------------------------------------- /js/page/my/img/ic_remove@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_remove@3x.png -------------------------------------------------------------------------------- /js/page/my/img/ic_swap_vert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_swap_vert.png -------------------------------------------------------------------------------- /js/page/my/img/ic_view_quilt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_view_quilt.png -------------------------------------------------------------------------------- /res/images/ic_star_navbar@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_star_navbar@2x.png -------------------------------------------------------------------------------- /res/images/ic_star_navbar@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_star_navbar@3x.png -------------------------------------------------------------------------------- /res/images/ic_tiaozhuan_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_tiaozhuan_down.png -------------------------------------------------------------------------------- /res/images/ic_tiaozhuan_up@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_tiaozhuan_up@2x.png -------------------------------------------------------------------------------- /res/images/ic_tiaozhuan_up@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_tiaozhuan_up@3x.png -------------------------------------------------------------------------------- /res/images/ic_unstar_navbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_unstar_navbar.png -------------------------------------------------------------------------------- /resource/React-Native+Redux.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/resource/React-Native+Redux.jpg -------------------------------------------------------------------------------- /ios/GitHubPopular/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /js/page/my/img/ic_brightness@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_brightness@2x.png -------------------------------------------------------------------------------- /js/page/my/img/ic_brightness@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_brightness@3x.png -------------------------------------------------------------------------------- /js/page/my/img/ic_check_box@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_check_box@2x.png -------------------------------------------------------------------------------- /js/page/my/img/ic_check_box@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_check_box@3x.png -------------------------------------------------------------------------------- /js/page/my/img/ic_custom_theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_custom_theme.png -------------------------------------------------------------------------------- /js/page/my/img/ic_swap_vert@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_swap_vert@2x.png -------------------------------------------------------------------------------- /js/page/my/img/ic_swap_vert@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_swap_vert@3x.png -------------------------------------------------------------------------------- /js/page/my/img/ic_view_quilt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_view_quilt@2x.png -------------------------------------------------------------------------------- /js/page/my/img/ic_view_quilt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_view_quilt@3x.png -------------------------------------------------------------------------------- /res/images/ic_remove_white@36pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_remove_white@36pt.png -------------------------------------------------------------------------------- /res/images/ic_search_white_48pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_search_white_48pt.png -------------------------------------------------------------------------------- /res/images/ic_spinner_triangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_spinner_triangle.png -------------------------------------------------------------------------------- /res/images/ic_tiaozhuan_down@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_tiaozhuan_down@2x.png -------------------------------------------------------------------------------- /res/images/ic_tiaozhuan_down@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_tiaozhuan_down@3x.png -------------------------------------------------------------------------------- /res/images/ic_unstar_navbar@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_unstar_navbar@2x.png -------------------------------------------------------------------------------- /res/images/ic_unstar_navbar@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_unstar_navbar@3x.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | GitHub Popular 4 | 5 | -------------------------------------------------------------------------------- /js/page/my/img/ic_custom_language.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_custom_language.png -------------------------------------------------------------------------------- /js/page/my/img/ic_custom_theme@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_custom_theme@2x.png -------------------------------------------------------------------------------- /js/page/my/img/ic_custom_theme@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_custom_theme@3x.png -------------------------------------------------------------------------------- /js/page/my/img/ic_insert_emoticon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_insert_emoticon.png -------------------------------------------------------------------------------- /res/images/ic_more_vert_white_48pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_more_vert_white_48pt.png -------------------------------------------------------------------------------- /res/images/ic_remove_white_36pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_remove_white_36pt@2x.png -------------------------------------------------------------------------------- /res/images/ic_remove_white_36pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_remove_white_36pt@3x.png -------------------------------------------------------------------------------- /res/images/ic_search_white_48pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_search_white_48pt@2x.png -------------------------------------------------------------------------------- /res/images/ic_search_white_48pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_search_white_48pt@3x.png -------------------------------------------------------------------------------- /res/images/ic_unstar_transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_unstar_transparent.png -------------------------------------------------------------------------------- /js/page/my/img/ic_custom_language2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_custom_language2x.png -------------------------------------------------------------------------------- /js/page/my/img/ic_custom_language3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_custom_language3x.png -------------------------------------------------------------------------------- /js/page/my/img/ic_insert_emoticon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_insert_emoticon@2x.png -------------------------------------------------------------------------------- /js/page/my/img/ic_insert_emoticon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_insert_emoticon@3x.png -------------------------------------------------------------------------------- /res/images/ic_arrow_back_white_36pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_arrow_back_white_36pt.png -------------------------------------------------------------------------------- /res/images/ic_star_border_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_star_border_white_24dp.png -------------------------------------------------------------------------------- /res/images/ic_unstar_transparent@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_unstar_transparent@2x.png -------------------------------------------------------------------------------- /res/images/ic_unstar_transparent@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_unstar_transparent@3x.png -------------------------------------------------------------------------------- /resource/screenshot/GitHubPopular-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/resource/screenshot/GitHubPopular-1.jpg -------------------------------------------------------------------------------- /resource/screenshot/GitHubPopular-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/resource/screenshot/GitHubPopular-2.jpg -------------------------------------------------------------------------------- /resource/screenshot/GitHubPopular-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/resource/screenshot/GitHubPopular-3.jpg -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /res/images/ic_arrow_back_white_36pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_arrow_back_white_36pt@2x.png -------------------------------------------------------------------------------- /res/images/ic_arrow_back_white_36pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_arrow_back_white_36pt@3x.png -------------------------------------------------------------------------------- /res/images/ic_more_vert_white_48pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_more_vert_white_48pt@2x.png -------------------------------------------------------------------------------- /res/images/ic_more_vert_white_48pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/res/images/ic_more_vert_white_48pt@3x.png -------------------------------------------------------------------------------- /.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /js/model/TimeSpan.js: -------------------------------------------------------------------------------- 1 | 2 | export default function TimeSpan(showText,searchText){ 3 | this.showText=showText; 4 | this.searchText=searchText; 5 | } -------------------------------------------------------------------------------- /js/page/my/img/ic_check_box_outline_blank.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_check_box_outline_blank.png -------------------------------------------------------------------------------- /js/page/my/img/ic_check_box_outline_blank@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_check_box_outline_blank@2x.png -------------------------------------------------------------------------------- /js/page/my/img/ic_check_box_outline_blank@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/js/page/my/img/ic_check_box_outline_blank@3x.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/keystores/debug.keystore.properties: -------------------------------------------------------------------------------- 1 | key.store=debug.keystore 2 | key.alias=androiddebugkey 3 | key.store.password=android 4 | key.alias.password=android 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xhdpi/launch_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/android/app/src/main/res/drawable-xhdpi/launch_screen.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxhdpi/launch_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/android/app/src/main/res/drawable-xxhdpi/launch_screen.png -------------------------------------------------------------------------------- /ios/GitHubPopular/Images.xcassets/AppIcon.appiconset/120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/ios/GitHubPopular/Images.xcassets/AppIcon.appiconset/120.png -------------------------------------------------------------------------------- /ios/GitHubPopular/Images.xcassets/AppIcon.appiconset/180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/ios/GitHubPopular/Images.xcassets/AppIcon.appiconset/180.png -------------------------------------------------------------------------------- /android/keystores/BUCK: -------------------------------------------------------------------------------- 1 | keystore( 2 | name = 'debug', 3 | store = 'debug.keystore', 4 | properties = 'debug.keystore.properties', 5 | visibility = [ 6 | 'PUBLIC', 7 | ], 8 | ) 9 | -------------------------------------------------------------------------------- /js/model/ProjectModel.js: -------------------------------------------------------------------------------- 1 | /** 2 | * FavoriteDao 3 | * @flow 4 | */ 5 | 'use strict'; 6 | 7 | export default function ProjectModel(item,isFavorite){ 8 | this.item=item; 9 | this.isFavorite=isFavorite; 10 | } -------------------------------------------------------------------------------- /ios/GitHubPopular/Images.xcassets/LaunchImage.launchimage/LaunchScreen1242x2208.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/ios/GitHubPopular/Images.xcassets/LaunchImage.launchimage/LaunchScreen1242x2208.png -------------------------------------------------------------------------------- /ios/GitHubPopular/Images.xcassets/LaunchImage.launchimage/LaunchScreen640x960-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/ios/GitHubPopular/Images.xcassets/LaunchImage.launchimage/LaunchScreen640x960-1.png -------------------------------------------------------------------------------- /ios/GitHubPopular/Images.xcassets/LaunchImage.launchimage/LaunchScreen640x960.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/ios/GitHubPopular/Images.xcassets/LaunchImage.launchimage/LaunchScreen640x960.png -------------------------------------------------------------------------------- /ios/GitHubPopular/Images.xcassets/LaunchImage.launchimage/LaunchScreen750x1334.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/ios/GitHubPopular/Images.xcassets/LaunchImage.launchimage/LaunchScreen750x1334.png -------------------------------------------------------------------------------- /ios/GitHubPopular/Images.xcassets/LaunchImage.launchimage/LaunchScreen640 × 1136.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/ios/GitHubPopular/Images.xcassets/LaunchImage.launchimage/LaunchScreen640 × 1136.png -------------------------------------------------------------------------------- /ios/GitHubPopular/Images.xcassets/LaunchImage.launchimage/LaunchScreen640 × 1136-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/HEAD/ios/GitHubPopular/Images.xcassets/LaunchImage.launchimage/LaunchScreen640 × 1136-1.png -------------------------------------------------------------------------------- /index.android.js: -------------------------------------------------------------------------------- 1 | /** 2 | * GitHubPopular 3 | * @flow 4 | */ 5 | 6 | import { 7 | AppRegistry, 8 | } from 'react-native' 9 | import setup from './js/page/setup'; 10 | 11 | AppRegistry.registerComponent('GitHubPopular', () => setup); 12 | -------------------------------------------------------------------------------- /index.ios.js: -------------------------------------------------------------------------------- 1 | /** 2 | * GitHubPopular 3 | * @flow 4 | */ 5 | 6 | 7 | import { 8 | AppRegistry, 9 | } from 'react-native' 10 | import setup from './js/page/setup'; 11 | 12 | AppRegistry.registerComponent('GitHubPopular', () => setup); 13 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'GitHubPopular' 2 | 3 | include ':app' 4 | include ':react-native-splash-screen' 5 | project(':react-native-splash-screen').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-splash-screen/android') 6 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Sep 19 13:37:24 CST 2016 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-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /API.md: -------------------------------------------------------------------------------- 1 | ## GitHub Popular API 2 | - URL:https://api.github.com/search/repositories? 3 | - 查询所有的:q=stars:>1&sort=stars 4 | - 分类查询:q=ios&sort=stars 5 | 6 | 7 | ## Usage: 8 | // var API_URL ='https://api.github.com/search/repositories?q=ios&sort=stars'; 9 | 10 | // var API_URL ='https://api.github.com/search/repositories?q=stars:>1&sort=stars'; -------------------------------------------------------------------------------- /android/app/src/main/res/layout/launch_screen.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | -------------------------------------------------------------------------------- /ios/GitHubPopular/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | @interface AppDelegate : UIResponder 13 | 14 | @property (nonatomic, strong) UIWindow *window; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /js/util/Utils.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | export default class Utils { 4 | static objectIsValueEqual(object1, object2) { 5 | for (var _key in object1) { 6 | if (object1._key !== object2._key)return false; 7 | } 8 | return true; 9 | } 10 | /** 11 | * 检查该Item是否被收藏 12 | * **/ 13 | static checkFavorite(item,items) { 14 | for (var i = 0, len = items.length; i < len; i++) { 15 | if (item.id.toString() === items[i]) { 16 | return true; 17 | } 18 | } 19 | return false; 20 | } 21 | } -------------------------------------------------------------------------------- /ios/GitHubPopular/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | #import "AppDelegate.h" 13 | 14 | int main(int argc, char * argv[]) { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bundles/ 2 | 3 | # OSX 4 | # 5 | .DS_Store 6 | 7 | # Xcode 8 | # 9 | build/ 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | *.xccheckout 20 | *.moved-aside 21 | DerivedData 22 | *.hmap 23 | *.ipa 24 | *.xcuserstate 25 | project.xcworkspace 26 | 27 | # Android/IJ 28 | # 29 | *.iml 30 | .idea 31 | .gradle 32 | local.properties 33 | 34 | # node.js 35 | # 36 | node_modules/ 37 | npm-debug.log 38 | 39 | # BUCK 40 | buck-out/ 41 | \.buckd/ 42 | android/app/libs 43 | android/keystores/debug.keystore 44 | -------------------------------------------------------------------------------- /js/util/Cancelable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Cancelable 3 | * @flow 4 | **/ 5 | 'use strict' 6 | 7 | export default function makeCancelable(promise){ 8 | let hasCanceled_ = false; 9 | const wrappedPromise = new Promise((resolve, reject) => { 10 | promise.then((val) => 11 | hasCanceled_ ? reject({isCanceled: true}) : resolve(val) 12 | ); 13 | promise.catch((error) => 14 | hasCanceled_ ? reject({isCanceled: true}) : reject(error) 15 | ); 16 | }); 17 | 18 | return { 19 | promise: wrappedPromise, 20 | cancel() { 21 | hasCanceled_ = true; 22 | }, 23 | }; 24 | } -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.0' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | mavenLocal() 18 | jcenter() 19 | maven { 20 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 21 | url "$rootDir/../node_modules/react-native/android" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.tags1: -------------------------------------------------------------------------------- 1 | !_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ 2 | !_TAG_FILE_SORTED 0 /0=unsorted, 1=sorted, 2=foldcase/ 3 | !_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/ 4 | !_TAG_PROGRAM_NAME Exuberant Ctags // 5 | !_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ 6 | !_TAG_PROGRAM_VERSION 5.8 // 7 | ReactNative /Users/penn/Desktop/React Native/GitHubPopular/app/AboutPage.js /^var ReactNative=require('react-native');$/;" variable line:7 8 | render /Users/penn/Desktop/React Native/GitHubPopular/app/AboutPage.js /^ render:function() {$/;" function line:18 9 | NavigationBar /Users/penn/Desktop/React Native/GitHubPopular/app/AboutPage.js /^var NavigationBar=require('.\/NavigationBar')$/;" variable line:16 10 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/jph/githubpopular/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.jph.githubpopular; 2 | 3 | 4 | import android.os.Bundle; 5 | 6 | import com.cboy.rn.splashscreen.SplashScreen; 7 | import com.facebook.react.ReactActivity; 8 | 9 | public class MainActivity extends ReactActivity { 10 | 11 | /** 12 | * Returns the name of the main component registered from JavaScript. 13 | * This is used to schedule rendering of the component. 14 | */ 15 | @Override 16 | protected String getMainComponentName() { 17 | return "GitHubPopular"; 18 | } 19 | 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | SplashScreen.show(this,true); 23 | super.onCreate(savedInstanceState); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "GitHubPopular", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node node_modules/react-native/local-cli/cli.js start" 7 | }, 8 | "dependencies": { 9 | "GitHubTrending": "^2.0.0", 10 | "react": "15.3.0", 11 | "react-native": "0.32.0", 12 | "react-native-check-box": "^1.0.0", 13 | "react-native-easy-toast": "^1.0.2", 14 | "react-native-htmlview": "^0.5.0", 15 | "react-native-parallax-scroll-view": "^0.19.0", 16 | "react-native-scrollable-tab-view": "^0.5.3", 17 | "react-native-sortable-listview": "^0.1.1", 18 | "react-native-splash-screen": "^1.0.9", 19 | "react-native-tab-navigator": "^0.3.3" 20 | }, 21 | "devDependencies": { 22 | "babel-cli": "^6.11.4" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /js/common/BaseCommon.js: -------------------------------------------------------------------------------- 1 | /** 2 | * BaseCommon 3 | * 公共逻辑处理 4 | * @flow 5 | */ 6 | 'use strict'; 7 | 8 | 9 | import React, {Component} from 'react'; 10 | import { 11 | BackAndroid, 12 | } from 'react-native'; 13 | 14 | 15 | export default class BaseCommon { 16 | constructor(props) { 17 | this._onHardwareBackPress = this.onHardwareBackPress.bind(this); 18 | this.props = props; 19 | } 20 | componentDidMount() { 21 | if(this.props.backPress)BackAndroid.addEventListener('hardwareBackPress',this._onHardwareBackPress); 22 | } 23 | componentWillUnmount() { 24 | if(this.props.backPress)BackAndroid.removeEventListener('hardwareBackPress',this._onHardwareBackPress); 25 | } 26 | onHardwareBackPress(e){ 27 | return this.props.backPress(e); 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /res/data/keys.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "path": "stars:>1", 4 | "name": "ALL", 5 | "short_name": "ALL", 6 | "checked": true 7 | }, 8 | { 9 | "path": "Android", 10 | "name": "Android", 11 | "checked": true 12 | }, 13 | { 14 | "path": "iOS", 15 | "name": "iOS", 16 | "checked": true 17 | }, 18 | { 19 | "path": "react-native", 20 | "name": "React Native", 21 | "checked": false 22 | }, 23 | { 24 | "path": "MySQL", 25 | "name": "MySQL", 26 | "checked": false 27 | }, 28 | { 29 | "path": " AngularJS", 30 | "name": " AngularJS", 31 | "checked": false 32 | }, 33 | { 34 | "path": " jQuery", 35 | "name": " jQuery", 36 | "checked": false 37 | }, 38 | { 39 | "path": " react", 40 | "name": " React", 41 | "checked": false 42 | } 43 | ] -------------------------------------------------------------------------------- /ios/GitHubPopularTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /js/expand/dao/ThemeDao.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ThemeDao 3 | * @flow 4 | */ 5 | 'use strict'; 6 | 7 | import { 8 | AsyncStorage, 9 | } from 'react-native'; 10 | import ThemeFactory, {ThemeFlags} from '../../../res/styles/ThemeFactory' 11 | const THEME_KEY = 'theme_key' 12 | 13 | export default class ThemeDao { 14 | getTheme() { 15 | return new Promise((resolve, reject)=> { 16 | AsyncStorage.getItem(THEME_KEY, (error, result)=> { 17 | if (error) { 18 | reject(error); 19 | return; 20 | } 21 | if (!result) { 22 | this.save(ThemeFlags.Default); 23 | result = ThemeFlags.Default; 24 | } 25 | resolve(ThemeFactory.createTheme(result)); 26 | }); 27 | }); 28 | } 29 | 30 | save(themeFlag) { 31 | AsyncStorage.setItem(THEME_KEY, themeFlag, (error, result)=> { 32 | 33 | }); 34 | } 35 | } -------------------------------------------------------------------------------- /res/data/Config.json: -------------------------------------------------------------------------------- 1 | { 2 | "items": [ 3 | "RNStudyNotes", 4 | "GitHubPopular", 5 | "TakePhoto", 6 | "react-native-awesome", 7 | "GroupListView", 8 | "react-native-check-box", 9 | "react-native-easy-toast", 10 | "PUtils", 11 | "IncrementalUpdate", 12 | "BreakPointUploadUtil" 13 | ], 14 | "info": { 15 | "html_url": "https://github.com/crazycodeboy/", 16 | "url": "https://api.github.com/repos/crazycodeboy/", 17 | "currentRepoUrl": "https://api.github.com/repos/crazycodeboy/GitHubPopular" 18 | }, 19 | "author": { 20 | "name": "CrazyCodeBoy", 21 | "description": "专注于移动开发,分享知识,共享快乐。", 22 | "avatar": "http://avatar.csdn.net/1/1/E/1_fengyuzhengfan.jpg", 23 | "backgroundImg": "http://www.devio.org/io/GitHubPopular/img/for_githubpopular_about_me.jpg", 24 | "avatar1": "http://www.devio.org/io/GitHubPopular/img/ic_app.png", 25 | "backgroundImg1": "http://www.rui2.net/uploadfile/output/2015/0322/44b845bf8ae757a2.jpg", 26 | "url": "http://www.devio.org/" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useDeprecatedNdk=true 21 | 22 | 23 | MYAPP_RELEASE_STORE_FILE=JPH_android_key 24 | MYAPP_RELEASE_KEY_ALIAS=android_key 25 | 26 | -------------------------------------------------------------------------------- /js/common/MPColors.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MPColor 3 | * @flow 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const LOCATION_COLORS = { 9 | 'HERBST': '#00E3AD', 10 | 'HERBST A': '#00E3AD', 11 | 'HERBST B': '#00E3AD', 12 | 'HACKER X': '#4D99EF', 13 | 'HACKER Y': '#CF72B1', 14 | 'COWELL': '#6A6AD5', 15 | 'COWELL C': '#6A6AD5', 16 | 'FOOD TENT': '#FFCD3B', 17 | }; 18 | 19 | function colorForLocation(location) { 20 | if (!location) { 21 | return 'black'; 22 | } 23 | 24 | var color = LOCATION_COLORS[location.toUpperCase()]; 25 | if (!color) { 26 | console.warn(`Location '${location}' has no color`); 27 | color = 'black'; 28 | } 29 | return color; 30 | } 31 | 32 | function colorForTopic(count, index) { 33 | const hue = Math.round(360 * index / (count + 1)); 34 | return `hsl(${hue}, 74%, 65%)`; 35 | } 36 | 37 | module.exports = { 38 | actionText: '#3FB4CF', 39 | inactiveText: '#9B9B9B', 40 | darkText: '#032250', 41 | lightText: '#7F91A7', 42 | cellBorder: '#EEEEEE', 43 | darkBackground: '#183E63', 44 | colorForLocation, 45 | colorForTopic, 46 | }; 47 | -------------------------------------------------------------------------------- /js/page/setup.js: -------------------------------------------------------------------------------- 1 | 2 | import React,{Component} from 'react' 3 | import { 4 | Navigator, 5 | }from 'react-native' 6 | 7 | import RepositoryUtils from '../expand/dao/RepositoryUtils' 8 | import WelcomePage from './WelcomePage' 9 | 10 | 11 | function setup(){ 12 | 13 | RepositoryUtils.init(true); 14 | 15 | class Root extends Component { 16 | 17 | constructor(props) { 18 | super(props); 19 | this.state = { 20 | }; 21 | } 22 | _renderScene(route, navigator) { 23 | let Component = route.component; 24 | return ( 25 | 26 | ); 27 | } 28 | render() { 29 | return ( 30 | this._renderScene(e, i)} 36 | /> 37 | ); 38 | } 39 | } 40 | 41 | return ; 42 | } 43 | 44 | module.exports = setup; -------------------------------------------------------------------------------- /android/app/src/main/java/com/jph/githubpopular/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.jph.githubpopular; 2 | 3 | import android.app.Application; 4 | import com.facebook.react.ReactApplication; 5 | import com.cboy.rn.splashscreen.SplashScreenReactPackage; 6 | import com.facebook.react.ReactNativeHost; 7 | import com.facebook.react.ReactPackage; 8 | import com.facebook.react.shell.MainReactPackage; 9 | import java.util.Arrays; 10 | import java.util.List; 11 | 12 | public class MainApplication extends Application implements ReactApplication { 13 | 14 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { 15 | @Override 16 | protected boolean getUseDeveloperSupport() { 17 | return BuildConfig.DEBUG; 18 | } 19 | 20 | @Override 21 | protected List getPackages() { 22 | return Arrays.asList( 23 | new MainReactPackage(), 24 | new SplashScreenReactPackage() 25 | ); 26 | } 27 | }; 28 | 29 | @Override 30 | public ReactNativeHost getReactNativeHost() { 31 | return mReactNativeHost; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /res/styles/GlobalStyles.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 全局样式 3 | * @flow 4 | */ 5 | import { 6 | Dimensions, 7 | } from 'react-native' 8 | 9 | const {height, width} = Dimensions.get('window'); 10 | 11 | module.exports ={ 12 | line: { 13 | flex: 1, 14 | height: 0.4, 15 | opacity:0.5, 16 | backgroundColor: 'darkgray', 17 | }, 18 | cell_container: { 19 | flex: 1, 20 | backgroundColor: 'white', 21 | padding: 10, 22 | marginLeft: 5, 23 | marginRight: 5, 24 | marginVertical: 3, 25 | borderColor: '#dddddd', 26 | borderStyle: null, 27 | borderWidth: 0.5, 28 | borderRadius: 2, 29 | shadowColor: 'gray', 30 | shadowOffset: {width:0.5, height: 0.5}, 31 | shadowOpacity: 0.4, 32 | shadowRadius: 1, 33 | elevation:2 34 | }, 35 | listView_container:{ 36 | flex: 1, 37 | backgroundColor: '#f3f3f4', 38 | }, 39 | backgroundColor: '#f3f3f4', 40 | listView_height:(height-(20+40)), 41 | window_height:height, 42 | window_width:width, 43 | nav_bar_height_ios:44, 44 | nav_bar_height_android:50, 45 | 46 | }; -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /ios/GitHubPopular/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "29x29", 26 | "scale" : "3x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "40x40", 36 | "scale" : "3x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "57x57", 41 | "scale" : "1x" 42 | }, 43 | { 44 | "idiom" : "iphone", 45 | "size" : "57x57", 46 | "scale" : "2x" 47 | }, 48 | { 49 | "size" : "60x60", 50 | "idiom" : "iphone", 51 | "filename" : "120.png", 52 | "scale" : "2x" 53 | }, 54 | { 55 | "size" : "60x60", 56 | "idiom" : "iphone", 57 | "filename" : "180.png", 58 | "scale" : "3x" 59 | } 60 | ], 61 | "info" : { 62 | "version" : 1, 63 | "author" : "xcode" 64 | } 65 | } -------------------------------------------------------------------------------- /js/expand/dao/LanguageDao.js: -------------------------------------------------------------------------------- 1 | /** 2 | * RespositoryDao 3 | * @flow 4 | */ 5 | 'use strict'; 6 | 7 | import { 8 | AsyncStorage, 9 | } from 'react-native'; 10 | import langsData from '../../../res/data/langs.json' 11 | import keysData from '../../../res/data/keys.json' 12 | 13 | export var FLAG_LANGUAGE = {flag_language: 'language_dao_language', flag_key: 'language_dao_key'} 14 | 15 | export default class LanguageDao{ 16 | constructor(flag) { 17 | this.flag = flag; 18 | } 19 | fetch(){ 20 | return new Promise((resolve,reject)=>{ 21 | AsyncStorage.getItem(this.flag,(error,result)=>{ 22 | if(error){ 23 | reject(error); 24 | return; 25 | } 26 | if (!result){ 27 | var data=this.flag===FLAG_LANGUAGE.flag_language? langsData:keysData; 28 | this.save(data); 29 | resolve(data); 30 | }else { 31 | try { 32 | resolve(JSON.parse(result)); 33 | } catch (e) { 34 | reject(error); 35 | } 36 | } 37 | }); 38 | }); 39 | } 40 | save(objectData){ 41 | var stringData=JSON.stringify(objectData); 42 | AsyncStorage.setItem(this.flag,stringData,(error,result)=>{ 43 | 44 | }); 45 | } 46 | } -------------------------------------------------------------------------------- /js/expand/dao/RepositoryDao.js: -------------------------------------------------------------------------------- 1 | /** 2 | * RespositoryDao 3 | * @flow 4 | */ 5 | 'use strict'; 6 | 7 | import { 8 | AsyncStorage, 9 | } from 'react-native'; 10 | 11 | export var FLAG_STORAGE = {flag_popular: 'popular', flag_trending: 'trending'} 12 | 13 | export default class RepositoryDao { 14 | constructor(flag) { 15 | this.flag = flag; 16 | } 17 | saveRepository = function (key, items, callback) { 18 | AsyncStorage.setItem(this.getKeyWithFlag(key), JSON.stringify(items), callback); 19 | } 20 | getRepository = function (key) { 21 | return new Promise((resolve, reject)=> { 22 | AsyncStorage.getItem(this.getKeyWithFlag(key), (error, result)=> { 23 | if (!error) { 24 | try { 25 | resolve(JSON.parse(result)); 26 | } catch (e) { 27 | reject(e); 28 | console.error(e); 29 | } 30 | } else { 31 | reject(error); 32 | console.error(error); 33 | } 34 | }); 35 | }); 36 | } 37 | removeRepository = function (key) { 38 | AsyncStorage.removeItem(this.getKeyWithFlag(key), (error, result)=> { 39 | console.log(error); 40 | }); 41 | } 42 | getKeyWithFlag(key){ 43 | return this.flag + '_' + key; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /ios/GitHubPopular/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | zh_CN 7 | CFBundleDisplayName 8 | GitHub Popular 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSAllowsArbitraryLoads 30 | 31 | 32 | NSLocationWhenInUseUsageDescription 33 | 34 | UIRequiredDeviceCapabilities 35 | 36 | armv7 37 | 38 | UISupportedInterfaceOrientations 39 | 40 | UIInterfaceOrientationPortrait 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /res/styles/ThemeFactory.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 主题 3 | * @flow 4 | */ 5 | 6 | 7 | import { 8 | StyleSheet, 9 | } from 'react-native' 10 | 11 | export const ThemeFlags = { 12 | Default:'#4caf50', 13 | Red: '#F44336', 14 | Pink:'#E91E63', 15 | Purple:'#9C27B0', 16 | DeepPurple:'#673AB7', 17 | Indigo:'#3F51B5', 18 | Blue:'#2196F3', 19 | LightBlue:'#03A9F4', 20 | Cyan:'#00BCD4', 21 | Teal:'#009688', 22 | Green:'#4CAF50', 23 | LightGreen:'#8BC34A', 24 | Lime:'#CDDC39', 25 | Yellow:'#FFEB3B', 26 | Amber:'#FFC107', 27 | Orange:'#FF9800', 28 | DeepOrange:'#FF5722', 29 | Brown:'#795548', 30 | Grey:'#9E9E9E', 31 | BlueGrey:'#607D8B', 32 | Black:'#000000' 33 | } 34 | 35 | export default class ThemeFactory { 36 | // constructor(themeFlag) { 37 | // this.themeFlag = themeFlag; 38 | // this.theme = this.createTheme(); 39 | // } 40 | 41 | static createTheme(themeFlag) { 42 | return { 43 | themeColor:themeFlag, 44 | styles:StyleSheet.create({ 45 | selectedTitleStyle:{ 46 | color: themeFlag 47 | }, 48 | tabBarSelectedIcon: { 49 | tintColor: themeFlag 50 | }, 51 | navBar:{ 52 | backgroundColor:themeFlag, 53 | }, 54 | themeColor:{ 55 | color:themeFlag 56 | }, 57 | 58 | }) 59 | } 60 | } 61 | } 62 | 63 | -------------------------------------------------------------------------------- /js/page/WelcomePage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 欢迎页 3 | * @flow 4 | * **/ 5 | import React, {Component} from 'react'; 6 | import { 7 | StyleSheet, 8 | View, 9 | Text, 10 | InteractionManager, 11 | Platform, 12 | } from 'react-native' 13 | import HomePage from './HomePage' 14 | import ThemeDao from '../expand/dao/ThemeDao' 15 | import SplashScreen from 'react-native-splash-screen' 16 | 17 | export default class WelcomePage extends Component { 18 | 19 | componentDidMount() { 20 | const {navigator} = this.props; 21 | new ThemeDao().getTheme().then((data=>{ 22 | this.theme=data; 23 | })); 24 | this.timer = setTimeout(() => { 25 | InteractionManager.runAfterInteractions(() => { 26 | SplashScreen.hide(); 27 | navigator.resetTo({ 28 | component: HomePage, 29 | name: 'HomePage', 30 | params:{ 31 | theme:this.theme 32 | } 33 | }); 34 | }); 35 | }, 500); 36 | } 37 | componentWillUnmount() { 38 | this.timer && clearTimeout(this.timer); 39 | } 40 | render() { 41 | return ( 42 | 43 | {/**/} 44 | 45 | ); 46 | } 47 | 48 | } 49 | const styles = StyleSheet.create({ 50 | container:{ 51 | flex:1, 52 | } 53 | }) -------------------------------------------------------------------------------- /js/util/ArrayUtils.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | export default class ArrayUtils { 4 | /** 5 | * 更新数组,若item已存在则将其从数组中删除,若不存在则将其添加到数组 6 | * **/ 7 | static updateArray(array,item){ 8 | for (var i = 0, len = array.length; i < len; i++) { 9 | var temp = array[i]; 10 | if (item=== temp) { 11 | array.splice(i, 1); 12 | return; 13 | } 14 | } 15 | array.push(item); 16 | } 17 | /** 18 | * 向数组中添加元素,若元素与存在则不添加 19 | * **/ 20 | static add(array,item){ 21 | if(!array)return; 22 | for(var i=0,l=array.length;i 35 | 36 | {this.props.badge} 37 | 38 | 39 | ); 40 | } 41 | return ( 42 | 43 | 44 | 45 | 46 | {this.props.title} 47 | 48 | {badge} 49 | 50 | 51 | ); 52 | } 53 | } 54 | 55 | var styles = StyleSheet.create({ 56 | container: { 57 | flexDirection: 'row', 58 | height: 50, 59 | alignItems: 'center', 60 | paddingHorizontal: 20, 61 | }, 62 | icon: { 63 | marginRight: 20, 64 | }, 65 | title: { 66 | flex: 1, 67 | fontSize: 17, 68 | color: MPColors.lightText, 69 | }, 70 | selectedTitle: { 71 | color: MPColors.darkText, 72 | }, 73 | badge: { 74 | backgroundColor: '#DC3883', 75 | paddingHorizontal: 10, 76 | paddingVertical: 2, 77 | borderRadius: 10, 78 | }, 79 | badgeText: { 80 | fontSize: 12, 81 | color: 'white', 82 | }, 83 | }) 84 | -------------------------------------------------------------------------------- /js/page/WebViewPage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * WebViewPage 3 | * @flow 4 | **/ 5 | 'use strict' 6 | import React, {Component} from 'react' 7 | import { 8 | Image, 9 | ScrollView, 10 | StyleSheet, 11 | WebView, 12 | Platform, 13 | TouchableOpacity, 14 | Text, 15 | View, 16 | } from 'react-native' 17 | import NavigationBar from '../common/NavigationBar' 18 | import GlobalStyles from '../../res/styles/GlobalStyles' 19 | import ViewUtils from '../util/ViewUtils' 20 | const WEBVIEW_REF = 'webview'; 21 | 22 | 23 | export default class WebViewPage extends Component { 24 | constructor(props) { 25 | super(props); 26 | this.state = { 27 | url: this.props.url, 28 | canGoBack: false, 29 | title: this.props.title, 30 | theme: this.props.theme 31 | } 32 | } 33 | 34 | onBackPress(e) { 35 | if (this.state.canGoBack) { 36 | this.refs[WEBVIEW_REF].goBack(); 37 | } else { 38 | this.props.navigator.pop(); 39 | } 40 | } 41 | 42 | onNavigationStateChange(navState) { 43 | this.setState({ 44 | canGoBack: navState.canGoBack, 45 | url: navState.url, 46 | }); 47 | } 48 | 49 | render() { 50 | return ( 51 | 52 | this.onBackPress())} 57 | title={this.state.title} 58 | /> 59 | this.onNavigationStateChange(e)} 63 | source={{uri: this.state.url}}/> 64 | 65 | 66 | ); 67 | } 68 | } 69 | 70 | const styles = StyleSheet.create({ 71 | container: { 72 | flex: 1, 73 | backgroundColor: '#ffffff', 74 | }, 75 | }) 76 | -------------------------------------------------------------------------------- /ios/GitHubPopularTests/GitHubPopularTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | #import 12 | 13 | #import "RCTLog.h" 14 | #import "RCTRootView.h" 15 | 16 | #define TIMEOUT_SECONDS 600 17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!" 18 | 19 | @interface GithubPopularTests : XCTestCase 20 | 21 | @end 22 | 23 | @implementation GithubPopularTests 24 | 25 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 26 | { 27 | if (test(view)) { 28 | return YES; 29 | } 30 | for (UIView *subview in [view subviews]) { 31 | if ([self findSubviewInView:subview matching:test]) { 32 | return YES; 33 | } 34 | } 35 | return NO; 36 | } 37 | 38 | - (void)testRendersWelcomeScreen 39 | { 40 | UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; 41 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 42 | BOOL foundElement = NO; 43 | 44 | __block NSString *redboxError = nil; 45 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 46 | if (level >= RCTLogLevelError) { 47 | redboxError = message; 48 | } 49 | }); 50 | 51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 54 | 55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 57 | return YES; 58 | } 59 | return NO; 60 | }]; 61 | } 62 | 63 | RCTSetLogFunction(RCTDefaultLogFunction); 64 | 65 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 66 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 67 | } 68 | 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GitHub Popular 2 | 3 | [![Download](https://img.shields.io/badge/Download-v1.0.3-ff69b4.svg) ](http://www.devio.org/io/GitHubPopular/) 4 | [ ![PRs Welcome](https://img.shields.io/badge/PRs-Welcome-brightgreen.svg)](https://github.com/crazycodeboy/GitHubPopular/pulls)[ ![GitHubPopular release](https://img.shields.io/github/release/crazycodeboy/GitHubPopular.svg?maxAge=2592000?style=flat-square)](https://github.com/crazycodeboy/GitHubPopular/releases) 5 | [ ![language English](https://img.shields.io/badge/language-English-feb252.svg)](https://github.com/crazycodeboy/GitHubPopular/blob/master/README.en.md) 6 | 7 | 这是一个用来查看GitHub最受欢迎与最热项目的App,它基于React Native支持Android和iOS双平台。[#最新版React Native+Redux打造点这里☞#](http://coding.imooc.com/class/304.html) 8 | 9 | 10 | ## 目录 11 | 12 | * [能够Get到的技术](#能够Get到的技术) 13 | * [功能与特性](#功能与特性) 14 | * [下载安装](#下载安装) 15 | * [预览图](#预览图) 16 | * [运行调试](#运行调试) 17 | 18 | 19 | ## 能够Get到的技术 20 | 21 | [![能够Get到的技术](https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/master/resource/React-Native%2BRedux.jpg)](http://coding.imooc.com/class/304.html) 22 | 23 | ## 功能与特性 24 | 25 | * 支持订阅 50 多种编程语言; 26 | * 支持添加/删除编程语言,并支持自定义它们的排序; 27 | * 支持收藏喜欢的项目; 28 | * 支持多种颜色主题自由切换; 29 | * 支持搜索,并自持自定义订阅关键字; 30 | * 支持分享,轻松将自己喜欢的项目分享给好友; 31 | 32 | ## 下载安装 33 | 34 | [![App Store](http://www.devio.org/io/GitHubPopular/img/app%20store%20icon.png)](https://itunes.apple.com/cn/app/github-popular/id1169908238?l=zh&ls=1&mt=8) 35 | [![百度手机助手](https://raw.githubusercontent.com/crazycodeboy/crazycodeboy.github.io/master/io/GitHubPopular/img/baidushoujizhushou.png)](http://shouji.baidu.com/software/10123273.html) 36 | [![应用宝](https://raw.githubusercontent.com/crazycodeboy/crazycodeboy.github.io/master/io/GitHubPopular/img/yingyingbao.png)](http://sj.qq.com/myapp/detail.htm?apkName=com.jph.githubpopular) 37 | 38 | 39 | ## 预览图 40 | 41 | ![GitHub Popular](https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/master/resource/screenshot/GitHubPopular-1.jpg) 42 | 43 | ![GitHub Popular](https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/master/resource/screenshot/GitHubPopular-2.jpg) 44 | 45 | ![GitHub Popular](https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/master/resource/screenshot/GitHubPopular-3.jpg) 46 | 47 | # 运行调试 48 | 49 | 1. 准备React Native环境,可参考: [Requirements](https://facebook.github.io/react-native/docs/getting-started.html#requirements)。 50 | 2. Clone [GitHubPopular](https://github.com/crazycodeboy/GitHubPopular.git),然后终端进入项目根目录。 51 | 3. 终端运行 `npm i`。 52 | 4. 然后运行 `react-native run-ios` 或 `react-native run-android`。 53 | 5. Ok,有问题可以提[issues](https://github.com/crazycodeboy/GitHubPopular/issues)出来 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /js/expand/dao/FavoriteDao.js: -------------------------------------------------------------------------------- 1 | /** 2 | * FavoriteDao 3 | * @flow 4 | */ 5 | 'use strict'; 6 | 7 | 8 | import { 9 | AsyncStorage, 10 | } from 'react-native'; 11 | 12 | const FAVORITE_KEY_PREFIX='favorite_' 13 | 14 | export default class FavoriteDao{ 15 | constructor(flag) { 16 | this.flag = flag; 17 | this.favoriteKey=FAVORITE_KEY_PREFIX+flag; 18 | } 19 | saveFavoriteItem(key,vaule,callback) { 20 | AsyncStorage.setItem(key,vaule,(error,result)=>{ 21 | if (!error) {//更新Favorite的key 22 | this.updateFavoriteKeys(key,true); 23 | } 24 | }); 25 | } 26 | /** 27 | * 更新Favorite key集合 28 | * @param isAdd true 添加,false 删除 29 | * **/ 30 | updateFavoriteKeys(key,isAdd){ 31 | AsyncStorage.getItem(this.favoriteKey,(error,result)=>{ 32 | if (!error) { 33 | var favoriteKeys=[]; 34 | if (result) { 35 | favoriteKeys=JSON.parse(result); 36 | } 37 | var index=favoriteKeys.indexOf(key); 38 | if(isAdd){ 39 | if (index===-1)favoriteKeys.push(key); 40 | }else { 41 | if (index!==-1)favoriteKeys.splice(index, 1); 42 | } 43 | AsyncStorage.setItem(this.favoriteKey,JSON.stringify(favoriteKeys)); 44 | } 45 | }); 46 | } 47 | getFavoriteKeys(){//获取收藏的Respository对应的key 48 | 49 | return new Promise((resolve,reject)=>{ 50 | AsyncStorage.getItem(this.favoriteKey,(error,result)=>{ 51 | if (!error) { 52 | try { 53 | resolve(JSON.parse(result)); 54 | } catch (e) { 55 | reject(error); 56 | } 57 | }else { 58 | reject(error); 59 | } 60 | }); 61 | }); 62 | } 63 | removeFavoriteItem(key) { 64 | AsyncStorage.removeItem(key,(error,result)=>{ 65 | if (!error) { 66 | this.updateFavoriteKeys(key,false); 67 | } 68 | }); 69 | } 70 | 71 | getAllItems() { 72 | return new Promise((resolve,reject)=> { 73 | this.getFavoriteKeys().then((keys)=> { 74 | var items = []; 75 | if (keys) { 76 | AsyncStorage.multiGet(keys, (err, stores) => { 77 | try { 78 | stores.map((result, i, store) => { 79 | // get at each store's key/value so you can work with it 80 | let key = store[i][0]; 81 | let value = store[i][1]; 82 | if (value)items.push(JSON.parse(value)); 83 | }); 84 | resolve(items); 85 | } catch (e) { 86 | reject(e); 87 | } 88 | }); 89 | } else { 90 | resolve(items); 91 | } 92 | }).catch((e)=> { 93 | reject(e); 94 | }) 95 | }) 96 | } 97 | } 98 | 99 | -------------------------------------------------------------------------------- /ios/GitHubPopular/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import "AppDelegate.h" 11 | 12 | #import "RCTRootView.h" 13 | #import "SplashScreen.h" 14 | @implementation AppDelegate 15 | 16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 17 | { 18 | NSURL *jsCodeLocation; 19 | 20 | /** 21 | * Loading JavaScript code - uncomment the one you want. 22 | * 23 | * OPTION 1 24 | * Load from development server. Start the server from the repository root: 25 | * 26 | * $ npm start 27 | * 28 | * To run on device, change `localhost` to the IP address of your computer 29 | * (you can get this by typing `ifconfig` into the terminal and selecting the 30 | * `inet` value under `en0:`) and make sure your computer and iOS device are 31 | * on the same Wi-Fi network. 32 | */ 33 | 34 | // jsCodeLocation = [NSURL URLWithString:@"http://192.168.6.155:8081/index.ios.bundle?platform=ios&dev=true"]; 35 | // jsCodeLocation = [NSURL URLWithString:@"http://192.168.7.108:8081/index.ios.bundle?platform=ios&dev=true"]; 36 | jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"]; 37 | 38 | /** 39 | * OPTION 2 40 | * Load from pre-bundled file on disk. The static bundle is automatically 41 | * generated by the "Bundle React Native code and images" build step when 42 | * running the project on an actual device or running the project on the 43 | * simulator in the "Release" build configuration. 44 | */ 45 | 46 | // jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 47 | 48 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 49 | moduleName:@"GitHubPopular" 50 | initialProperties:nil 51 | launchOptions:launchOptions]; 52 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 53 | 54 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 55 | UIViewController *rootViewController = [UIViewController new]; 56 | rootViewController.view = rootView; 57 | self.window.rootViewController = rootViewController; 58 | [self.window makeKeyAndVisible]; 59 | [SplashScreen show]; 60 | return YES; 61 | } 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /android/app/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 /usr/local/Cellar/android-sdk/24.3.3/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 | 19 | # Disabling obfuscation is useful if you collect stack traces from production crashes 20 | # (unless you are using a system that supports de-obfuscate the stack traces). 21 | -dontobfuscate 22 | 23 | # React Native 24 | 25 | # Keep our interfaces so they can be used by other ProGuard rules. 26 | # See http://sourceforge.net/p/proguard/bugs/466/ 27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip 28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters 29 | -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip 30 | 31 | # Do not strip any method/class that is annotated with @DoNotStrip 32 | -keep @com.facebook.proguard.annotations.DoNotStrip class * 33 | -keep @com.facebook.common.internal.DoNotStrip class * 34 | -keepclassmembers class * { 35 | @com.facebook.proguard.annotations.DoNotStrip *; 36 | @com.facebook.common.internal.DoNotStrip *; 37 | } 38 | 39 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { 40 | void set*(***); 41 | *** get*(); 42 | } 43 | 44 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } 45 | -keep class * extends com.facebook.react.bridge.NativeModule { *; } 46 | -keepclassmembers,includedescriptorclasses class * { native ; } 47 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } 48 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } 49 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } 50 | 51 | -dontwarn com.facebook.react.** 52 | 53 | # okhttp 54 | 55 | -keepattributes Signature 56 | -keepattributes *Annotation* 57 | -keep class okhttp3.** { *; } 58 | -keep interface okhttp3.** { *; } 59 | -dontwarn okhttp3.** 60 | 61 | # okio 62 | 63 | -keep class sun.misc.Unsafe { *; } 64 | -dontwarn java.nio.file.* 65 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 66 | -dontwarn okio.** 67 | -------------------------------------------------------------------------------- /js/util/ViewUtils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ViewUtils 3 | * @flow 4 | **/ 5 | 'use strict' 6 | 7 | import React from 'react'; 8 | import { 9 | TouchableHighlight, 10 | Image, 11 | TouchableOpacity, 12 | StyleSheet, 13 | Text, 14 | View, 15 | } from 'react-native'; 16 | 17 | export default class ViewUtils { 18 | static getSettingItem(callBack, icon, text, tintStyle, expandableIco) { 19 | return ( 20 | 22 | 23 | 24 | {icon ? 25 | : 27 | 28 | } 29 | {text} 30 | 31 | 39 | 40 | 41 | ) 42 | } 43 | static getMoreButton(callBack) { 44 | return 49 | 50 | 54 | 55 | 56 | } 57 | 58 | static getLeftButton(callBack) { 59 | return 62 | 65 | 66 | } 67 | } 68 | 69 | const styles = StyleSheet.create({ 70 | setting_item_container: { 71 | backgroundColor: 'white', 72 | padding: 10, height: 60, 73 | alignItems: 'center', 74 | justifyContent: 'space-between', 75 | flexDirection: 'row' 76 | }, 77 | }) -------------------------------------------------------------------------------- /README.en.md: -------------------------------------------------------------------------------- 1 | # GitHubPopular 2 | 3 | [![Download](https://img.shields.io/badge/Download-v1.0.3-ff69b4.svg) ](http://www.devio.org/io/GitHubPopular/) 4 | [ ![PRs Welcome](https://img.shields.io/badge/PRs-Welcome-brightgreen.svg)](https://github.com/crazycodeboy/GitHubPopular/pulls)[ ![GitHubPopular release](https://img.shields.io/github/release/crazycodeboy/GitHubPopular.svg?maxAge=2592000?style=flat-square)](https://github.com/crazycodeboy/GitHubPopular/releases) 5 | [ ![语言 中文](https://img.shields.io/badge/语言-中文-red.svg)](https://github.com/crazycodeboy/GitHubPopular) 6 | 7 | This is a GitHub most popular repositories viewer with React Native. [#The latest version of React Native+Redux builds here☞#](http://coding.imooc.com/class/304.html) 8 | 9 | ## Contents 10 | 11 | * [Used technology](#used-technology) 12 | * [Features](#features) 13 | * [DownLoad](#downLoad) 14 | * [Screenshot](#screenshot) 15 | * [Running and debugging](#running-and-debugging) 16 | 17 | ## Used technology 18 | 19 | [![Used technology](https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/master/resource/React-Native%2BRedux.jpg)](http://coding.imooc.com/class/304.html) 20 | 21 | ## Features 22 | 23 | * Supports subscription to more than 50 programming languages; 24 | * Support for adding / deleting programming languages and support for customizing their sorting; 25 | * Support favorite projects; 26 | * Support multiple color themes to switch freely; 27 | * Support search, and self-sustaining custom subscription keywords; 28 | * Support to share, easy to share their favorite projects to friends; 29 | 30 | 31 | ## DownLoad 32 | 33 | [![App Store](http://www.devio.org/io/GitHubPopular/img/app%20store%20icon.png)](https://itunes.apple.com/cn/app/github-popular/id1169908238?l=zh&ls=1&mt=8) 34 | [![百度手机助手](https://raw.githubusercontent.com/crazycodeboy/crazycodeboy.github.io/master/io/GitHubPopular/img/baidushoujizhushou.png)](http://shouji.baidu.com/software/10123273.html) 35 | [![应用宝](https://raw.githubusercontent.com/crazycodeboy/crazycodeboy.github.io/master/io/GitHubPopular/img/yingyingbao.png)](http://sj.qq.com/myapp/detail.htm?apkName=com.jph.githubpopular) 36 | ## Screenshot 37 | 38 | ![GitHub Popular](https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/master/resource/screenshot/GitHubPopular-1.jpg) 39 | 40 | ![GitHub Popular](https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/master/resource/screenshot/GitHubPopular-2.jpg) 41 | 42 | ![GitHub Popular](https://raw.githubusercontent.com/crazycodeboy/GitHubPopular/master/resource/screenshot/GitHubPopular-3.jpg) 43 | 44 | ## Running and debugging 45 | 46 | 1. Prepare your environment: [Requirements](http://facebook.github.io/react-native/docs/getting-started.html#requirements) 47 | 2. Clone [GitHubPopular](https://github.com/crazycodeboy/GitHubPopular.git), and goto the project root directory. 48 | 3. run `npm i`. 49 | 4. run `react-native run-ios` or `react-native run-android`. 50 | 5. Yeah. You make it. 51 | 52 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | # We fork some components by platform. 4 | .*/*.web.js 5 | .*/*.android.js 6 | 7 | # Some modules have their own node_modules with overlap 8 | .*/node_modules/node-haste/.* 9 | 10 | # Ugh 11 | .*/node_modules/babel.* 12 | .*/node_modules/babylon.* 13 | .*/node_modules/invariant.* 14 | 15 | # Ignore react and fbjs where there are overlaps, but don't ignore 16 | # anything that react-native relies on 17 | .*/node_modules/fbjs/lib/Map.js 18 | .*/node_modules/fbjs/lib/ErrorUtils.js 19 | 20 | # Flow has a built-in definition for the 'react' module which we prefer to use 21 | # over the currently-untyped source 22 | .*/node_modules/react/react.js 23 | .*/node_modules/react/lib/React.js 24 | .*/node_modules/react/lib/ReactDOM.js 25 | 26 | .*/__mocks__/.* 27 | .*/__tests__/.* 28 | 29 | .*/commoner/test/source/widget/share.js 30 | 31 | # Ignore commoner tests 32 | .*/node_modules/commoner/test/.* 33 | 34 | # See https://github.com/facebook/flow/issues/442 35 | .*/react-tools/node_modules/commoner/lib/reader.js 36 | 37 | # Ignore jest 38 | .*/node_modules/jest-cli/.* 39 | 40 | # Ignore Website 41 | .*/website/.* 42 | 43 | # Ignore generators 44 | .*/local-cli/generator.* 45 | 46 | # Ignore BUCK generated folders 47 | .*\.buckd/ 48 | 49 | # Ignore RNPM 50 | .*/local-cli/rnpm/.* 51 | 52 | .*/node_modules/is-my-json-valid/test/.*\.json 53 | .*/node_modules/iconv-lite/encodings/tables/.*\.json 54 | .*/node_modules/y18n/test/.*\.json 55 | .*/node_modules/spdx-license-ids/spdx-license-ids.json 56 | .*/node_modules/spdx-exceptions/index.json 57 | .*/node_modules/resolve/test/subdirs/node_modules/a/b/c/x.json 58 | .*/node_modules/resolve/lib/core.json 59 | .*/node_modules/jsonparse/samplejson/.*\.json 60 | .*/node_modules/json5/test/.*\.json 61 | .*/node_modules/ua-parser-js/test/.*\.json 62 | .*/node_modules/builtin-modules/builtin-modules.json 63 | .*/node_modules/binary-extensions/binary-extensions.json 64 | .*/node_modules/url-regex/tlds.json 65 | .*/node_modules/joi/.*\.json 66 | .*/node_modules/isemail/.*\.json 67 | .*/node_modules/tr46/.*\.json 68 | 69 | 70 | [include] 71 | 72 | [libs] 73 | node_modules/react-native/Libraries/react-native/react-native-interface.js 74 | node_modules/react-native/flow 75 | flow/ 76 | 77 | [options] 78 | module.system=haste 79 | 80 | esproposal.class_static_fields=enable 81 | esproposal.class_instance_fields=enable 82 | 83 | experimental.strict_type_args=true 84 | 85 | munge_underscores=true 86 | 87 | module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub' 88 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' 89 | 90 | suppress_type=$FlowIssue 91 | suppress_type=$FlowFixMe 92 | suppress_type=$FixMe 93 | 94 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-7]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 95 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-7]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 96 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 97 | 98 | [version] 99 | ^0.30.0 100 | -------------------------------------------------------------------------------- /js/page/my/CustomTheme.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义主题 3 | * @flow 4 | * **/ 5 | import React, {Component} from "react"; 6 | import { 7 | StyleSheet, 8 | View, 9 | Image, 10 | Modal, Text, 11 | Platform, 12 | ScrollView, 13 | TouchableHighlight 14 | } from "react-native"; 15 | import ThemeFactory, {ThemeFlags} from "../../../res/styles/ThemeFactory"; 16 | import ThemeDao from "../../expand/dao/ThemeDao"; 17 | import GlobalStyles from '../../../res/styles/GlobalStyles' 18 | 19 | export default class CustomTheme extends Component { 20 | 21 | constructor(props) { 22 | super(props); 23 | this.themeDao = new ThemeDao(); 24 | } 25 | 26 | onSelectTheme(themeKey) { 27 | this.themeDao.save(ThemeFlags[themeKey]); 28 | this.props.onClose(); 29 | this.props.homeComponent.onThemeChange(ThemeFactory.createTheme(ThemeFlags[themeKey])); 30 | } 31 | 32 | renderCustomThemeView() { 33 | return ( { 38 | this.props.onClose(); 39 | }} 40 | > 41 | 42 | {this.renderThemeItems()} 43 | 44 | ) 45 | } 46 | 47 | getThemeItem(themeKey) { 48 | return ( 49 | this.onSelectTheme(themeKey)}> 53 | 54 | {themeKey} 55 | 56 | 57 | ); 58 | } 59 | 60 | renderThemeItems() { 61 | var views = []; 62 | for (let i = 0, keys = Object.keys(ThemeFlags), l = keys.length; i < l; i += 3) { 63 | key1 = keys[i], key2 = keys[i + 1], key3 = keys[i + 2]; 64 | views.push( 65 | {this.getThemeItem(key1)} 66 | {this.getThemeItem(key2)} 67 | {this.getThemeItem(key3)} 68 | ) 69 | } 70 | return views; 71 | } 72 | 73 | render() { 74 | let view = this.props.visible ? 75 | {this.renderCustomThemeView()} 76 | : null; 77 | return view 78 | } 79 | 80 | } 81 | const styles = StyleSheet.create({ 82 | modalContainer: { 83 | flex: 1, 84 | margin: 10, 85 | marginTop: Platform.OS === 'ios' ? 20 : 10, 86 | backgroundColor: 'white', 87 | borderRadius: 3, 88 | shadowColor: 'gray', 89 | shadowOffset: {width: 2, height: 2}, 90 | shadowOpacity: 0.5, 91 | shadowRadius: 2, 92 | padding: 3 93 | }, 94 | themeItem: { 95 | flex: 1, 96 | height: 120, 97 | margin: 3, 98 | padding: 3, 99 | borderRadius: 2, 100 | alignItems: 'center', 101 | justifyContent: 'center' 102 | }, 103 | themeText: { 104 | color: 'white', 105 | fontWeight: '500', 106 | fontSize: 16, 107 | } 108 | }) -------------------------------------------------------------------------------- /ios/GitHubPopular/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /js/page/about/AboutPage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AboutPage 3 | * 关于 4 | * @flow 5 | */ 6 | 'use strict'; 7 | 8 | 9 | import React, {Component} from 'react'; 10 | import { 11 | Image, 12 | StyleSheet, 13 | Linking, 14 | View, 15 | } from 'react-native'; 16 | 17 | import WebViewPage from '../../page/WebViewPage'; 18 | import AboutMePage from '../../page/about/AboutMePage'; 19 | import RepositoryUtils from '../../expand/dao/RepositoryUtils'; 20 | import ViewUtils from '../../util/ViewUtils' 21 | import GlobalStyles from '../../../res/styles/GlobalStyles' 22 | import config from '../../../res/data/Config.json' 23 | import {MORE_MENU} from '../../common/MoreMenu' 24 | import AboutCommon from './AboutCommon' 25 | 26 | export default class AboutPage extends Component { 27 | constructor(props) { 28 | super(props); 29 | this.aboutCommon=new AboutCommon(props,(dic)=>this.updateState(dic)); 30 | this.repositories=[]; 31 | this.state = { 32 | projectModels: null, 33 | author:config.author 34 | } 35 | } 36 | 37 | componentDidMount() { 38 | this.initCurrentRepository(); 39 | this.aboutCommon.componentDidMount(); 40 | } 41 | componentWillUnmount(){ 42 | this.aboutCommon.componentWillUnmount(); 43 | } 44 | async initCurrentRepository() { 45 | let data=await RepositoryUtils.init().fetchCurrentRepository(); 46 | if(!data)return; 47 | this.repositories.push(data); 48 | this.aboutCommon.updateFavorite(this.repositories); 49 | } 50 | async getConfig() { 51 | let data = await RepositoryUtils.init().getConfig(); 52 | if (!data)data = config; 53 | this.setState({ 54 | author: data.author, 55 | }) 56 | } 57 | updateState(dic){ 58 | this.setState(dic); 59 | } 60 | onClick(tab) { 61 | let TargetComponent, params = {...this.props,menuType:tab}; 62 | switch (tab) { 63 | case MORE_MENU.About_Author: 64 | TargetComponent=AboutMePage; 65 | break; 66 | case MORE_MENU.Website: 67 | TargetComponent = WebViewPage; 68 | params.title='GitHubPopular'; 69 | let url=!this.repositories[0]? config.info.html_url:this.repositories[0].homepage; 70 | params.url=url; 71 | break; 72 | case MORE_MENU.Feedback: 73 | Linking.openURL('mailto://crazycodeboy@gmail.com'); 74 | break; 75 | 76 | } 77 | if (TargetComponent) { 78 | this.props.navigator.push({ 79 | component: TargetComponent, 80 | params: params, 81 | }); 82 | } 83 | } 84 | render() { 85 | let content= 86 | {this.aboutCommon.renderRepository(this.state.projectModels)} 87 | {ViewUtils.getSettingItem(()=>this.onClick(MORE_MENU.Website), require('../../../res/images/ic_computer.png'),MORE_MENU.Website, this.props.theme.styles.tabBarSelectedIcon)} 88 | 89 | {ViewUtils.getSettingItem(()=>this.onClick(MORE_MENU.About_Author), require('../my/img/ic_insert_emoticon.png'), MORE_MENU.About_Author, this.props.theme.styles.tabBarSelectedIcon)} 90 | 91 | {ViewUtils.getSettingItem(()=>this.onClick(MORE_MENU.Feedback), require('../../../res/images/ic_feedback.png'), MORE_MENU.Feedback, this.props.theme.styles.tabBarSelectedIcon)} 92 | 93 | return this.aboutCommon.render(content, { 94 | 'name': 'GitHub Popular', 95 | 'description': 'This is a GitHub most popular repositories and trending repositories viewer with React Native.', 96 | 'avatar':this.state.author.avatar1, 97 | 'backgroundImg':this.state.author.backgroundImg1, 98 | }); 99 | } 100 | } 101 | const styles = StyleSheet.create({ 102 | container: { 103 | flex: 1, 104 | }, 105 | }); 106 | -------------------------------------------------------------------------------- /js/expand/dao/DataRepository.js: -------------------------------------------------------------------------------- 1 | /** 2 | * DataRepository 3 | * 刷新从网络获取;非刷新从本地获取, 4 | * 若本地数据过期,先返回本地数据,然后返回从网络获取的数据 5 | * @flow 6 | */ 7 | 'use strict'; 8 | 9 | import { 10 | AsyncStorage, 11 | } from 'react-native'; 12 | import Trending from "GitHubTrending"; 13 | export var FLAG_STORAGE = {flag_popular: 'popular', flag_trending: 'trending'} 14 | 15 | export default class DataRepository { 16 | constructor(flag) { 17 | this.flag = flag; 18 | if(flag===FLAG_STORAGE.flag_trending)this.treding=new Trending(); 19 | } 20 | 21 | saveRepository(url, items, callback) { 22 | if (!items || !url)return; 23 | let wrapData={items:items,date:new Date().getTime()}; 24 | AsyncStorage.setItem(url, JSON.stringify(wrapData), callback); 25 | } 26 | 27 | fetchRepository(url) { 28 | return new Promise((resolve, reject)=> { 29 | this.fetchLocalRepository(url).then((wrapData)=> { 30 | if (wrapData) { 31 | resolve(wrapData,true); 32 | } else { 33 | this.fetchNetRepository(url).then((data)=> { 34 | resolve(data); 35 | }).catch((error)=> { 36 | reject(error); 37 | }) 38 | } 39 | 40 | }).catch((error)=> { 41 | console.log('fetchLocalRepository fail:'+error); 42 | this.fetchNetRepository(url).then((data)=> { 43 | resolve(data); 44 | }).catch((error=> { 45 | reject(error); 46 | })) 47 | }) 48 | }) 49 | } 50 | 51 | fetchLocalRepository(url) { 52 | return new Promise((resolve, reject)=> { 53 | AsyncStorage.getItem(url, (error, result)=> { 54 | if (!error) { 55 | try { 56 | resolve(JSON.parse(result)); 57 | } catch (e) { 58 | reject(e); 59 | console.error(e); 60 | } 61 | } else { 62 | reject(error); 63 | console.error(error); 64 | } 65 | }) 66 | }) 67 | } 68 | 69 | fetchNetRepository(url) { 70 | return new Promise((resolve, reject)=> { 71 | if (this.flag === FLAG_STORAGE.flag_popular) { 72 | fetch(url) 73 | .then((response)=>response.json()) 74 | .catch((error)=> { 75 | reject(error); 76 | }).then((responseData)=> { 77 | if (!responseData||!responseData.items) { 78 | reject(new Error('responseData is null')); 79 | return; 80 | } 81 | resolve(responseData.items); 82 | this.saveRepository(url,responseData.items) 83 | }).done(); 84 | } else { 85 | this.treding.fetchTrending(url) 86 | .then((items)=> { 87 | if (!items) { 88 | reject(new Error('responseData is null')); 89 | return; 90 | } 91 | resolve(items); 92 | this.saveRepository(url,items) 93 | }).catch((error)=> { 94 | reject(error); 95 | }) 96 | } 97 | }) 98 | } 99 | 100 | removeRepository(url) { 101 | AsyncStorage.removeItem(url, (error, result)=> { 102 | if(error)console.log(error); 103 | }); 104 | } 105 | 106 | checkDate(longTime) { 107 | let currentDate = new Date(); 108 | let targetDate = new Date(); 109 | targetDate.setTime(longTime); 110 | if (currentDate.getMonth() !== targetDate.getMonth())return false; 111 | if (currentDate.getDate() !== targetDate.getDate())return false; 112 | if (currentDate.getHours() - targetDate.getHours() > 4)return false; 113 | // if (currentDate.getMinutes() - targetDate.getMinutes() > 1)return false; 114 | return true; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /js/page/RepositoryDetail.js: -------------------------------------------------------------------------------- 1 | /** 2 | * RepositoryDetail 3 | * @flow 4 | **/ 5 | 'use strict' 6 | import React, {Component} from 'react' 7 | import { 8 | Image, 9 | ScrollView, 10 | StyleSheet, 11 | WebView, 12 | Platform, 13 | TouchableOpacity, 14 | Text, 15 | View, 16 | } from 'react-native' 17 | import NavigationBar from '../common/NavigationBar' 18 | import BaseCommon from '../common/BaseCommon' 19 | import FavoriteDao from '../expand/dao/FavoriteDao' 20 | import ViewUtils from '../util/ViewUtils' 21 | const TRENDING_URL = 'https://github.com/' 22 | var WEBVIEW_REF = 'webview'; 23 | 24 | export default class RepositoryDetail extends Component { 25 | constructor(props) { 26 | super(props); 27 | this.baseCommon=new BaseCommon({...props,backPress:(e)=>this.onBackPress(e)}); 28 | var url = this.props.projectModel.item.html_url ? this.props.projectModel.item.html_url 29 | : TRENDING_URL + this.props.projectModel.item.fullName; 30 | var title = this.props.projectModel.item.full_name ? this.props.projectModel.item.full_name 31 | : this.props.projectModel.item.fullName; 32 | this.state = { 33 | isFavorite: this.props.projectModel.isFavorite, 34 | favoriteIcon: this.props.projectModel.isFavorite ? require('../../res/images/ic_star.png') : require('../../res/images/ic_star_navbar.png'), 35 | url: url, 36 | canGoBack: false, 37 | title: title, 38 | theme: this.props.theme 39 | } 40 | } 41 | 42 | componentDidMount() { 43 | this.baseCommon.componentDidMount(); 44 | this.favoriteDao = new FavoriteDao(this.props.flag); 45 | } 46 | 47 | componentWillUnmount() { 48 | this.baseCommon.componentWillUnmount(); 49 | if (this.props.parentComponent)this.props.parentComponent.updateFavorite(); 50 | } 51 | 52 | onBackPress(e){ 53 | this.onBack(); 54 | return true; 55 | } 56 | 57 | setFavoriteState(isFavorite) { 58 | this.setState({ 59 | isFavorite: isFavorite, 60 | favoriteIcon: isFavorite ? require('../../res/images/ic_star.png') : require('../../res/images/ic_star_navbar.png') 61 | }) 62 | } 63 | 64 | onRightButtonClick() {//favoriteIcon单击回调函数 65 | var projectModel = this.props.projectModel; 66 | this.setFavoriteState(projectModel.isFavorite = !projectModel.isFavorite); 67 | var key = projectModel.item.fullName ? projectModel.item.fullName : projectModel.item.id.toString(); 68 | if (projectModel.isFavorite) { 69 | this.favoriteDao.saveFavoriteItem(key, JSON.stringify(projectModel.item)); 70 | } else { 71 | this.favoriteDao.removeFavoriteItem(key); 72 | } 73 | } 74 | 75 | onBack() { 76 | if (this.state.canGoBack) { 77 | this.refs[WEBVIEW_REF].goBack(); 78 | } else { 79 | this.props.navigator.pop(); 80 | } 81 | } 82 | 83 | onNavigationStateChange(navState) { 84 | this.setState({ 85 | canGoBack: navState.canGoBack, 86 | url: navState.url, 87 | }); 88 | } 89 | 90 | renderRightButton() { 91 | return this.onRightButtonClick()}> 93 | 96 | 97 | } 98 | render() { 99 | let titleLayoutStyle=this.state.title.length>20?{paddingRight:30}:null; 100 | return ( 101 | 102 | this.onBack())} 105 | popEnabled={false} 106 | style={this.state.theme.styles.navBar} 107 | title={this.state.title} 108 | titleLayoutStyle={titleLayoutStyle} 109 | rightButton={this.renderRightButton()} 110 | /> 111 | this.onNavigationStateChange(e)} 115 | source={{uri: this.state.url}}/> 116 | 117 | 118 | ); 119 | } 120 | } 121 | 122 | const styles = StyleSheet.create({ 123 | container: { 124 | flex: 1, 125 | backgroundColor: '#ffffff', 126 | // marginBottom: Platform.OS === "ios" ? 50 : 0, 127 | }, 128 | }) 129 | -------------------------------------------------------------------------------- /js/expand/dao/RepositoryUtils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * DataRepository 3 | * 刷新从网络获取;非刷新从本地获取, 4 | * 若本地数据过期,先返回本地数据,然后返回从网络获取的数据 5 | * @flow 6 | */ 7 | 'use strict'; 8 | 9 | import { 10 | AsyncStorage, 11 | } from 'react-native'; 12 | import config from '../../../res/data/Config.json' 13 | const URL = 'http://www.devio.org/io/GitHubPopular/json/Config.json'; 14 | var repositoryUtils; 15 | export default class RepositoryUtils { 16 | constructor(isInit) { 17 | if (isInit)this.start(); 18 | } 19 | 20 | static init(isInit) { 21 | if (!repositoryUtils) { 22 | repositoryUtils = new RepositoryUtils(isInit); 23 | } 24 | return repositoryUtils; 25 | } 26 | 27 | start() { 28 | this.getConfig().then(result=> { 29 | this.config = JSON.parse(result); 30 | if (!this.checkDate(this.config.date, true)) { 31 | this.updateWithUrl(URL, true); 32 | this.updateRepositories(); 33 | } 34 | }).catch(error=> { 35 | this.config = {'data': config}; 36 | this.updateWithUrl(URL, true); 37 | this.updateRepositories(); 38 | }); 39 | 40 | } 41 | 42 | getConfig() { 43 | return new Promise((resolve, reject)=> { 44 | if(this.config){ 45 | resolve(this.config.data); 46 | return; 47 | } 48 | AsyncStorage.getItem(URL, (error, result)=> { 49 | if (error || !result) { 50 | reject(error); 51 | } else { 52 | resolve(result); 53 | } 54 | }) 55 | }) 56 | } 57 | 58 | updateWithUrl(url, isSaveDate) { 59 | fetch(url) 60 | .then((response)=>response.json()) 61 | .then((responseData)=> { 62 | if (responseData)this.saveRepository(url, responseData, isSaveDate) 63 | }).catch((error)=> { 64 | console.log(error); 65 | }); 66 | } 67 | 68 | updateRepositories() { 69 | let data = this.config.data; 70 | let url = data.info.url; 71 | for (let i = 0, l = data.items.length; i < l; i++) { 72 | this.updateWithUrl(url + data.items[i]); 73 | } 74 | } 75 | 76 | saveRepository(url, data, isSaveDate, callback) { 77 | if (!data || !url)return; 78 | if (isSaveDate) data = {data: data, date: new Date().getTime()}; 79 | AsyncStorage.setItem(url, JSON.stringify(data), callback); 80 | } 81 | 82 | fetchRepositories() { 83 | return new Promise((resolve, reject)=> { 84 | if (this.config) { 85 | let keys = []; 86 | let names = this.config.data.items; 87 | let url = this.config.data.info.url; 88 | for (let i = 0, l = names.length; i < l; i++) { 89 | keys.push(url + names[i]); 90 | } 91 | let items = []; 92 | AsyncStorage.multiGet(keys, (err, stores) => { 93 | try { 94 | stores.map((result, i, store) => { 95 | let key = store[i][0]; 96 | let value = store[i][1]; 97 | if (value)items.push(JSON.parse(value)); 98 | }); 99 | if(items.length===0)this.updateRepositories(); 100 | resolve(items); 101 | } catch (e) { 102 | reject(e); 103 | } 104 | }); 105 | } else { 106 | resolve(items); 107 | } 108 | }) 109 | } 110 | 111 | fetchCurrentRepository() { 112 | return new Promise((resolve, reject)=> { 113 | let key = this.config.data.info.currentRepoUrl; 114 | AsyncStorage.getItem(key, (error, result)=> { 115 | if (!error) { 116 | try { 117 | resolve(JSON.parse(result)); 118 | } catch (e) { 119 | reject(error); 120 | } 121 | } else { 122 | reject(error); 123 | } 124 | }); 125 | }); 126 | } 127 | 128 | checkDate(longTime, isWithDay) { 129 | let currentDate = new Date(); 130 | let targetDate = new Date(); 131 | targetDate.setTime(longTime); 132 | if (currentDate.getMonth() !== targetDate.getMonth())return false; 133 | if (currentDate.getDate() !== targetDate.getDate())return false; 134 | if (isWithDay)return true; 135 | if (currentDate.getHours() - targetDate.getHours() > 4)return false; 136 | // if (currentDate.getMinutes() - targetDate.getMinutes() > 1)return false; 137 | return true; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /ios/GitHubPopular.xcodeproj/xcshareddata/xcschemes/GitHubPopular.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 80 | 86 | 87 | 88 | 89 | 90 | 91 | 97 | 99 | 105 | 106 | 107 | 108 | 110 | 111 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /js/page/HomePage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 首页 3 | * @flow 4 | */ 5 | 6 | import React, {Component} from 'react'; 7 | 8 | import { 9 | StyleSheet, 10 | Image, 11 | View, 12 | } from 'react-native' 13 | import TabNavigator from 'react-native-tab-navigator' 14 | import PopularPage from './PopularPage' 15 | import TrendingPage from './TrendingPage' 16 | import FavoritePage from './FavoritePage' 17 | import MyPage from './my/MyPage' 18 | 19 | import ArrayUtils from '../util/ArrayUtils' 20 | 21 | export var FLAG_TAB = { 22 | flag_popularTab: 'flag_popularTab', flag_trendingTab: 'flag_trendingTab', 23 | flag_favoriteTab: 'flag_favoriteTab', flag_myTab: 'flag_myTab' 24 | } 25 | 26 | export default class HomePage extends Component { 27 | constructor(props) { 28 | super(props); 29 | this.subscribers = []; 30 | this.changedValues = { 31 | favorite: {popularChange: false, trendingChange: false}, 32 | my: {languageChange: false, keyChange: false, themeChange: false} 33 | }; 34 | let selectedTab = this.props.selectedTab ? this.props.selectedTab : FLAG_TAB.flag_popularTab; 35 | this.state = { 36 | selectedTab: selectedTab, 37 | theme: this.props.theme 38 | }; 39 | } 40 | 41 | addSubscriber(subscriber) { 42 | ArrayUtils.add(this.subscribers, subscriber); 43 | } 44 | 45 | removeSubscriber(subscriber) { 46 | ArrayUtils.remove(this.subscribers, subscriber); 47 | } 48 | 49 | onSelected(object) { 50 | // if (this.updateFavorite && 'popularTab' === object)this.updateFavorite(object); 51 | 52 | if (object !== this.state.selectedTab) { 53 | this.subscribers.forEach((item, index, arr)=> { 54 | if (typeof(item) == 'function')item(this.state.selectedTab, object); 55 | }) 56 | } 57 | if(object===FLAG_TAB.flag_popularTab)this.changedValues.favorite.popularChange=false; 58 | if(object===FLAG_TAB.flag_trendingTab)this.changedValues.favorite.trendingChange=false; 59 | 60 | this.setState({ 61 | selectedTab: object, 62 | }) 63 | 64 | } 65 | onReStart(jumpToTab){ 66 | this.props.navigator.resetTo({ 67 | component: HomePage, 68 | name: 'HomePage', 69 | params: { 70 | ...this.props, 71 | theme:this.state.theme, 72 | selectedTab: jumpToTab, 73 | } 74 | }); 75 | } 76 | onThemeChange(theme) { 77 | if (!theme)return; 78 | this.setState({ 79 | theme: theme 80 | }) 81 | this.changedValues.my.themeChange = true; 82 | this.subscribers.forEach((item, index, arr)=> { 83 | if (typeof(item) == 'function')item(theme); 84 | }) 85 | this.changedValues.my.themeChange = false; 86 | } 87 | 88 | _renderTab(Component, selectedTab, title, renderIcon) { 89 | return ( 90 | } 96 | renderSelectedIcon={() => } 99 | onPress={() => this.onSelected(selectedTab)}> 100 | 101 | 102 | ) 103 | } 104 | 105 | render() { 106 | return ( 107 | 108 | 112 | {this._renderTab(PopularPage, FLAG_TAB.flag_popularTab, 'Popular', require('../../res/images/ic_polular.png'))} 113 | {this._renderTab(TrendingPage, FLAG_TAB.flag_trendingTab, 'Trending', require('../../res/images/ic_trending.png'))} 114 | {this._renderTab(FavoritePage, FLAG_TAB.flag_favoriteTab, 'Favorite', require('../../res/images/ic_favorite.png'))} 115 | {this._renderTab(MyPage, FLAG_TAB.flag_myTab, 'My', require('../../res/images/ic_my.png'))} 116 | 117 | 118 | ) 119 | } 120 | } 121 | const styles = StyleSheet.create({ 122 | container:{ 123 | flex:1, 124 | // backgroundColor:'#fff', 125 | }, 126 | tabBarIcon: { 127 | width: 26, height: 26, 128 | resizeMode: 'contain', 129 | }, 130 | tabBarSelectedIcon: { 131 | width: 26, height: 26, 132 | resizeMode: 'contain', 133 | // tintColor:'#4caf50' 134 | } 135 | }) 136 | -------------------------------------------------------------------------------- /js/common/TrendingRepoCell.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @flow 5 | */ 6 | 'use strict'; 7 | 8 | import React, {Component} from 'react' 9 | import { 10 | Image, 11 | Platform, 12 | StyleSheet, 13 | Text, 14 | TouchableHighlight, 15 | TouchableNativeFeedback, 16 | View, 17 | Alert, 18 | } from 'react-native' 19 | import GlobalStyles from '../../res/styles/GlobalStyles' 20 | import HTMLView from 'react-native-htmlview' 21 | import WebViewPage from '../page/WebViewPage' 22 | 23 | export default class TrendingRepoCell extends Component { 24 | constructor(props) { 25 | super(props); 26 | this.state = { 27 | isFavorite: this.props.projectModel.isFavorite, 28 | favoriteIcon: this.props.projectModel.isFavorite ? require('../../res/images/ic_star.png') : require('../../res/images/ic_unstar_transparent.png'), 29 | }; 30 | } 31 | 32 | componentWillReceiveProps(nextProps) {//当从当前页面切换走,再切换回来后 33 | this.setFavoriteState(nextProps.projectModel.isFavorite) 34 | } 35 | 36 | setFavoriteState(isFavorite) { 37 | this.props.projectModel.isFavorite = isFavorite; 38 | this.setState({ 39 | isFavorite: isFavorite, 40 | favoriteIcon: isFavorite ? require('../../res/images/ic_star.png') : require('../../res/images/ic_unstar_transparent.png') 41 | }) 42 | } 43 | 44 | onPressFavorite() { 45 | this.setFavoriteState(!this.state.isFavorite) 46 | this.props.onFavorite(this.props.projectModel.item, !this.state.isFavorite) 47 | } 48 | 49 | render() { 50 | var item = this.props.projectModel.item; 51 | var TouchableElement = TouchableHighlight; 52 | var description='

'+item.description+'

'; 53 | return ( 54 | 59 | 60 | 61 | 62 | {item.fullName} 63 | 64 | 65 | 66 | {/**/} 67 | {/*{item.description}*/} 68 | {/**/} 69 | { 72 | this.props.navigator.push({ 73 | component: WebViewPage, 74 | params: { 75 | title:url, 76 | url:url, 77 | ...this.props 78 | }, 79 | }); 80 | }} 81 | stylesheet={{ 82 | p:styles.description, 83 | a:styles.description, 84 | }} 85 | /> 86 | 87 | {item.meta} 88 | 89 | 90 | 91 | Built by 92 | {item.contributors.map((result, i, arr) => { 93 | return 98 | }) 99 | } 100 | 101 | this.onPressFavorite()} underlayColor='transparent'> 104 | 108 | 109 | 110 | 111 | 112 | ); 113 | } 114 | } 115 | 116 | 117 | var styles = StyleSheet.create({ 118 | title: { 119 | fontSize: 16, 120 | marginBottom: 2, 121 | color: '#212121' 122 | }, 123 | description: { 124 | fontSize: 14, 125 | marginBottom: 2, 126 | color: '#757575' 127 | }, 128 | author: { 129 | fontSize: 14, 130 | marginBottom: 2, 131 | color: '#757575' 132 | }, 133 | }); 134 | 135 | -------------------------------------------------------------------------------- /js/common/MoreMenu.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 更多菜单 3 | * @flow 4 | */ 5 | 'use strict'; 6 | import React, {Component,PropTypes} from 'react' 7 | import { 8 | ListView, 9 | StyleSheet, 10 | RefreshControl, 11 | TouchableHighlight, 12 | Text, 13 | Image, 14 | Linking, 15 | View, 16 | } from 'react-native' 17 | import Popover from "../common/Popover"; 18 | import CustomKeyPage from "../page/my/CustomKeyPage" 19 | import SortKeyPagePage from "../page/my/SortKeyPagePage" 20 | import AboutPage from "../page/about/AboutPage" 21 | import AboutMePage from "../page/about/AboutMePage" 22 | import FavoritePage from "../page/FavoritePage" 23 | import {FLAG_LANGUAGE} from '../expand/dao/LanguageDao' 24 | export const MORE_MENU = { 25 | Custom_Language:'Custom Language', 26 | Sort_Language:'Sort Language', 27 | Custom_Theme:'Custom Theme', 28 | Custom_Key:'Custom Key', 29 | Sort_Key:'Sort Key', 30 | Remove_Key:'Remove Key', 31 | About_Author:'About Author', 32 | About:'About', 33 | Website:'Website', 34 | Feedback:'Feedback', 35 | } 36 | 37 | export default class MoreMenu extends Component { 38 | constructor(props) { 39 | super(props); 40 | this.state = { 41 | isVisible: false, 42 | buttonRect: {}, 43 | } 44 | } 45 | 46 | static propTypes = { 47 | contentStyle: View.propTypes.style, 48 | menus:PropTypes.array, 49 | } 50 | 51 | open() { 52 | this.showPopover(); 53 | } 54 | 55 | showPopover() { 56 | if (!this.props.anchorView)return; 57 | let anchorView=this.props.anchorView; 58 | if(anchorView instanceof FavoritePage){ 59 | anchorView=anchorView.refs.moreMenuButton; 60 | } 61 | anchorView.measure((ox, oy, width, height, px, py) => { 62 | this.setState({ 63 | isVisible: true, 64 | buttonRect: {x: px, y: py, width: width, height: height} 65 | }); 66 | }); 67 | } 68 | 69 | closePopover() { 70 | this.setState({ 71 | isVisible: false, 72 | }); 73 | if (typeof(this.props.onClose) == 'function')this.props.onClose(); 74 | } 75 | 76 | onMoreMenuSelect(tab) { 77 | this.closePopover(); 78 | if (typeof(this.props.onMoreMenuSelect) == 'function')this.props.onMoreMenuSelect(tab); 79 | let TargetComponent, params={...this.props,menuType:tab}; 80 | switch (tab) { 81 | case MORE_MENU.Custom_Key: 82 | TargetComponent = CustomKeyPage; 83 | params.flag=FLAG_LANGUAGE.flag_key; 84 | break; 85 | case MORE_MENU.Sort_Key: 86 | TargetComponent = SortKeyPagePage; 87 | params.flag=FLAG_LANGUAGE.flag_key; 88 | break; 89 | case MORE_MENU.Remove_Key: 90 | TargetComponent = CustomKeyPage; 91 | params.flag=FLAG_LANGUAGE.flag_key; 92 | break; 93 | case MORE_MENU.Custom_Language: 94 | TargetComponent = CustomKeyPage; 95 | params.flag=FLAG_LANGUAGE.flag_language; 96 | break; 97 | case MORE_MENU.Sort_Language: 98 | TargetComponent = SortKeyPagePage; 99 | params.flag=FLAG_LANGUAGE.flag_language; 100 | break; 101 | case MORE_MENU.About: 102 | TargetComponent = AboutPage; 103 | params.flag=FLAG_LANGUAGE.flag_language; 104 | break; 105 | case MORE_MENU.About_Author: 106 | TargetComponent = AboutMePage; 107 | params.flag=FLAG_LANGUAGE.flag_language; 108 | break; 109 | case MORE_MENU.Feedback: 110 | Linking.openURL('mailto:crazycodeboy@gmail.com'); 111 | break; 112 | 113 | } 114 | if (TargetComponent) { 115 | this.props.navigator.push({ 116 | component: TargetComponent, 117 | params: params, 118 | }); 119 | } 120 | } 121 | 122 | renderMoreView() { 123 | let view = this.closePopover()} 128 | contentStyle={{opacity:0.82,backgroundColor:'#343434'}} 129 | contentMarginRight={20} 130 | > 131 | 132 | {this.props.menus.map((result, i, arr) => { 133 | return this.onMoreMenuSelect(arr[i])} 134 | underlayColor='transparent'> 135 | 137 | {arr[i]} 138 | 139 | 140 | }) 141 | } 142 | 143 | 144 | ; 145 | return view; 146 | } 147 | 148 | render() { 149 | return (this.renderMoreView()); 150 | } 151 | 152 | } -------------------------------------------------------------------------------- /js/common/RepositoryCell.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @flow 5 | */ 6 | 'use strict'; 7 | 8 | import React, {Component} from 'react' 9 | import { 10 | Image, 11 | Platform, 12 | StyleSheet, 13 | Text, 14 | TouchableHighlight, 15 | TouchableNativeFeedback, 16 | View, 17 | Alert, 18 | } from 'react-native' 19 | import GlobalStyles from '../../res/styles/GlobalStyles' 20 | import HTMLView from 'react-native-htmlview' 21 | import WebViewPage from '../page/WebViewPage' 22 | 23 | 24 | export default class RespositoryCell extends Component { 25 | constructor(props) { 26 | super(props); 27 | this.state = { 28 | isFavorite: this.props.projectModel.isFavorite, 29 | favoriteIcon: this.props.projectModel.isFavorite ? require('../../res/images/ic_star.png') : require('../../res/images/ic_unstar_transparent.png'), 30 | }; 31 | } 32 | 33 | componentWillReceiveProps(nextProps) {//当从当前页面切换走,再切换回来后 34 | this.setFavoriteState(nextProps.projectModel.isFavorite) 35 | } 36 | 37 | setFavoriteState(isFavorite) { 38 | this.props.projectModel.isFavorite = isFavorite; 39 | this.setState({ 40 | isFavorite: isFavorite, 41 | favoriteIcon: isFavorite ? require('../../res/images/ic_star.png') : require('../../res/images/ic_unstar_transparent.png') 42 | }) 43 | } 44 | 45 | onPressFavorite() { 46 | this.setFavoriteState(!this.state.isFavorite) 47 | this.props.onFavorite(this.props.projectModel.item, !this.state.isFavorite) 48 | } 49 | 50 | render() { 51 | let item = this.props.projectModel.item? this.props.projectModel.item:this.props.projectModel; 52 | let TouchableElement = TouchableHighlight; 53 | let favoriteButton=this.props.projectModel.item? 54 | this.onPressFavorite()} underlayColor='transparent'> 57 | 61 | :null; 62 | let description='

'+item.description+'

'; 63 | return ( 64 | 69 | 70 | 71 | 72 | {item.full_name} 73 | 74 | 75 | 76 | {/**/} 77 | {/*{item.description}*/} 78 | {/**/} 79 | { 82 | this.props.navigator.push({ 83 | component: WebViewPage, 84 | params: { 85 | title:url, 86 | url:url, 87 | ...this.props 88 | }, 89 | }); 90 | }} 91 | stylesheet={{ 92 | p:styles.description, 93 | a:styles.description, 94 | }} 95 | /> 96 | 97 | 98 | Author: 99 | 103 | 104 | 105 | Stars: 106 | 107 | {item.stargazers_count} 108 | 109 | 110 | {favoriteButton} 111 | 112 | 113 | 114 | ); 115 | } 116 | } 117 | 118 | 119 | var styles = StyleSheet.create({ 120 | title: { 121 | fontSize: 16, 122 | marginBottom: 2, 123 | color: '#212121', 124 | flex:1 125 | }, 126 | description: { 127 | fontSize: 14, 128 | marginBottom: 2, 129 | color: '#757575' 130 | }, 131 | author: { 132 | fontSize: 14, 133 | marginBottom: 2, 134 | color: '#757575' 135 | }, 136 | }); 137 | 138 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /js/page/my/CustomKeyPage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 添加Trending语言,Popular 关键字 3 | * @flow 4 | * **/ 5 | 6 | import React, {Component} from 'react'; 7 | import { 8 | StyleSheet, 9 | ScrollView, 10 | View, 11 | Image, 12 | Alert 13 | } from 'react-native' 14 | import CheckBox from 'react-native-check-box' 15 | import NavigationBar from '../../common/NavigationBar' 16 | import BaseCommon from '../../common/BaseCommon' 17 | import LanguageDao,{FLAG_LANGUAGE} from '../../expand/dao/LanguageDao' 18 | import ArrayUtils from '../../util/ArrayUtils' 19 | import {MORE_MENU} from '../../common/MoreMenu' 20 | import ViewUtils from '../../util/ViewUtils' 21 | 22 | export default class CustomKeyPage extends Component { 23 | constructor(props) { 24 | super(props); 25 | this.baseCommon=new BaseCommon({...props,backPress:(e)=>this.onBackPress(e)}); 26 | this.changeValues=[]; 27 | this.isRemoveKey=this.props.menuType===MORE_MENU.Remove_Key; 28 | this.state = { 29 | dataArray: [] 30 | } 31 | } 32 | 33 | componentDidMount() { 34 | this.languageDao = new LanguageDao(this.props.flag); 35 | this.loadData(); 36 | this.baseCommon.componentDidMount(); 37 | } 38 | componentWillUnmount(){ 39 | this.baseCommon.componentWillUnmount(); 40 | } 41 | onBackPress(e){ 42 | this.onBack(); 43 | return true; 44 | } 45 | loadData() { 46 | this.languageDao.fetch().then((data)=> { 47 | this.setState({ 48 | dataArray: data 49 | }) 50 | }).catch((error)=> { 51 | console.log(error); 52 | }); 53 | } 54 | 55 | onClick(data) { 56 | if(!this.isRemoveKey)data.checked = !data.checked; 57 | ArrayUtils.updateArray(this.changeValues,data) 58 | } 59 | 60 | onSave() { 61 | if (this.changeValues.length ===0){ 62 | this.props.navigator.pop(); 63 | return; 64 | } 65 | if(this.isRemoveKey){ 66 | for(let i=0,l=this.changeValues.length;i 0) { 85 | Alert.alert( 86 | 'Confirm Exit', 87 | 'Do you want to save your changes before exitting?', 88 | [ 89 | { 90 | text: 'No', onPress: () => { 91 | this.props.navigator.pop(); 92 | } 93 | }, { 94 | text: 'Yes', onPress: () => { 95 | this.onSave(); 96 | } 97 | } 98 | ] 99 | ) 100 | } else { 101 | this.props.navigator.pop(); 102 | } 103 | } 104 | 105 | renderView() { 106 | if (!this.state.dataArray || this.state.dataArray.length === 0)return; 107 | var len = this.state.dataArray.length; 108 | var views = []; 109 | for (var i = 0, l = len - 2; i < l; i += 2) { 110 | views.push( 111 | 112 | 113 | {this.renderCheckBox(this.state.dataArray[i])} 114 | {this.renderCheckBox(this.state.dataArray[i + 1])} 115 | 116 | 117 | 118 | ) 119 | } 120 | views.push( 121 | 122 | 123 | {len % 2 === 0 ? this.renderCheckBox(this.state.dataArray[len - 2]) : null} 124 | {this.renderCheckBox(this.state.dataArray[len - 1])} 125 | 126 | 127 | ) 128 | return views; 129 | 130 | } 131 | 132 | renderCheckBox(data) { 133 | let leftText = data.name; 134 | let isChecked=this.isRemoveKey?false:data.checked; 135 | return ( 136 | this.onClick(data)} 139 | isChecked={isChecked} 140 | leftText={leftText} 141 | checkedImage={} 142 | unCheckedImage={} 143 | />); 144 | } 145 | 146 | render() { 147 | let rightButtonTitle=this.isRemoveKey? 'Remove':'Save'; 148 | let rightButtonConfig = { 149 | title: rightButtonTitle, 150 | handler:()=>this.onSave(), 151 | tintColor:'white', 152 | }; 153 | let navigationBar = 154 | this.onBack())} 157 | style={this.props.theme.styles.navBar} 158 | rightButton={rightButtonConfig}/>; 159 | return ( 160 | 161 | {navigationBar} 162 | 163 | {this.renderView()} 164 | 165 | 166 | ) 167 | } 168 | 169 | } 170 | 171 | const styles = StyleSheet.create({ 172 | container: { 173 | flex: 1, 174 | backgroundColor: '#f3f2f2' 175 | }, 176 | item: { 177 | flexDirection: 'row', 178 | }, 179 | line: { 180 | flex: 1, 181 | height: 0.3, 182 | backgroundColor: 'darkgray', 183 | }, 184 | }) -------------------------------------------------------------------------------- /js/page/my/SortKeyPagePage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 对Trending语言,Popular 关键字进行排序 3 | * @flow 4 | * **/ 5 | 6 | import React, {Component} from 'react'; 7 | import { 8 | StyleSheet, 9 | ScrollView, 10 | TouchableHighlight, 11 | View, 12 | Image, 13 | Text, 14 | Alert 15 | } from 'react-native' 16 | import SortableListView from 'react-native-sortable-listview' 17 | import NavigationBar from '../../common/NavigationBar' 18 | import BaseCommon from '../../common/BaseCommon' 19 | import LanguageDao, {FLAG_LANGUAGE} from '../../expand/dao/LanguageDao' 20 | import ArrayUtils from '../../util/ArrayUtils' 21 | import ViewUtils from '../../util/ViewUtils' 22 | 23 | export default class SortKeyPage extends Component { 24 | constructor(props) { 25 | super(props); 26 | this.baseCommon=new BaseCommon({...props,backPress:(e)=>this.onBackPress(e)}); 27 | this.dataArray=[]; 28 | this.sortResultArray=[]; 29 | this.originalCheckedArray=[]; 30 | this.state = { 31 | checkedArray: [] 32 | } 33 | } 34 | 35 | componentDidMount() { 36 | this.languageDao = new LanguageDao(this.props.flag); 37 | this.loadData(); 38 | this.baseCommon.componentDidMount(); 39 | } 40 | componentWillUnmount() { 41 | this.baseCommon.componentWillUnmount(); 42 | } 43 | onBackPress(){ 44 | this.onBack(); 45 | return true; 46 | } 47 | loadData() { 48 | this.languageDao.fetch().then((data)=> { 49 | this.getCheckedItems(data); 50 | }).catch((error)=> { 51 | console.log(error); 52 | }); 53 | } 54 | getCheckedItems(dataArray){ 55 | this.dataArray=dataArray; 56 | let checkedArray=[]; 57 | for(let i=0,j=dataArray.length;i { 103 | this.props.navigator.pop(); 104 | } 105 | }, { 106 | text: 'Yes', onPress: () => { 107 | this.onSave(true); 108 | } 109 | } 110 | ] 111 | ) 112 | } else { 113 | this.props.navigator.pop(); 114 | } 115 | } 116 | 117 | render() { 118 | let title = this.props.flag === FLAG_LANGUAGE.flag_language ? 'Sort Language' : 'Sort Key'; 119 | let rightButtonConfig = { 120 | title: 'Save', 121 | handler:()=>this.onSave(), 122 | tintColor:'white', 123 | }; 124 | let navigationBar = 125 | this.onBack())} 128 | style={this.props.theme.styles.navBar} 129 | rightButton={rightButtonConfig}/>; 130 | return ( 131 | 132 | {navigationBar} 133 | { 137 | this.state.checkedArray.splice(e.to, 0, this.state.checkedArray.splice(e.from, 1)[0]); 138 | this.forceUpdate(); 139 | }} 140 | renderRow={row => } 141 | /> 142 | 143 | ) 144 | } 145 | 146 | } 147 | 148 | class SortCell extends Component { 149 | render() { 150 | return 154 | 155 | 156 | {this.props.data.name} 157 | 158 | 159 | } 160 | } 161 | 162 | const styles = StyleSheet.create({ 163 | container: { 164 | flex: 1, 165 | backgroundColor: '#f3f2f2' 166 | }, 167 | hidden:{ 168 | height:0 169 | }, 170 | item:{ 171 | backgroundColor: "#F8F8F8", 172 | borderBottomWidth: 1, 173 | borderColor: '#eee', 174 | height:50, 175 | justifyContent:'center' 176 | }, 177 | line: { 178 | flex: 1, 179 | height: 0.3, 180 | backgroundColor: 'darkgray', 181 | }, 182 | }) 183 | -------------------------------------------------------------------------------- /res/data/langs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "path": "", 4 | "name": "All Language", 5 | "short_name": "All", 6 | "checked": true 7 | }, 8 | { 9 | "path": "unknown", 10 | "name": "Unknown", 11 | "checked": false 12 | }, 13 | { 14 | "path": "as3", 15 | "name": "ActionScript", 16 | "short_name": "AS", 17 | "checked": true 18 | }, 19 | { 20 | "path": "apacheconf", 21 | "name": "ApacheConf", 22 | "checked": true 23 | }, 24 | { 25 | "path": "nasm", 26 | "name": "Assembly", 27 | "short_name": "NASM", 28 | "checked": false 29 | }, 30 | { 31 | "path": "bat", 32 | "name": "Batchfile", 33 | "short_name": "BAT", 34 | "checked": false 35 | }, 36 | { 37 | "path": "c", 38 | "name": "C", 39 | "checked": false 40 | }, 41 | { 42 | "path": "csharp", 43 | "name": "C#", 44 | "checked": false 45 | }, 46 | { 47 | "path": "cpp", 48 | "name": "C++", 49 | "checked": false 50 | }, 51 | { 52 | "path": "cmake", 53 | "name": "CMake", 54 | "checked": false 55 | }, 56 | { 57 | "path": "css", 58 | "name": "CSS", 59 | "checked": false 60 | }, 61 | { 62 | "path": "clojure", 63 | "name": "Clojure", 64 | "checked": false 65 | }, 66 | { 67 | "path": "coffeescript", 68 | "name": "CoffeeScript", 69 | "checked": false 70 | }, 71 | { 72 | "path": "common-lisp", 73 | "short_name": "Lisp", 74 | "name": "Common Lisp", 75 | "checked": false 76 | }, 77 | { 78 | "path": "crystal", 79 | "name": "Crystal", 80 | "checked": false 81 | }, 82 | { 83 | "path": "d", 84 | "name": "D", 85 | "checked": false 86 | }, 87 | { 88 | "path": "dart", 89 | "name": "Dart", 90 | "checked": false 91 | }, 92 | { 93 | "path": "elixir", 94 | "name": "Elixir", 95 | "checked": false 96 | }, 97 | { 98 | "path": "emacs-lisp", 99 | "short_name": "Lisp", 100 | "name": "Emacs Lisp", 101 | "checked": false 102 | }, 103 | { 104 | "path": "erlang", 105 | "name": "Erlang", 106 | "checked": false 107 | }, 108 | { 109 | "path": "fsharp", 110 | "name": "F#", 111 | "checked": false 112 | }, 113 | { 114 | "path": "game-maker-language", 115 | "short_name": "GML", 116 | "name": "Game Maker Language", 117 | "checked": false 118 | }, 119 | { 120 | "path": "go", 121 | "name": "Go", 122 | "checked": false 123 | }, 124 | { 125 | "path": "groovy", 126 | "name": "Groovy", 127 | "checked": false 128 | }, 129 | { 130 | "path": "html", 131 | "name": "HTML", 132 | "checked": false 133 | }, 134 | { 135 | "path": "haskell", 136 | "name": "Haskell", 137 | "checked": false 138 | }, 139 | { 140 | "path": "haxe", 141 | "name": "Haxe", 142 | "checked": false 143 | }, 144 | { 145 | "path": "inno-setup", 146 | "short_name": "Inno", 147 | "name": "Inno Setup", 148 | "checked": false 149 | }, 150 | { 151 | "path": "java", 152 | "name": "Java", 153 | "checked": false 154 | }, 155 | { 156 | "path": "javascript", 157 | "short_name": "JS", 158 | "name": "JavaScript", 159 | "checked": false 160 | }, 161 | { 162 | "path": "julia", 163 | "name": "Julia", 164 | "checked": false 165 | }, 166 | { 167 | "path": "kotlin", 168 | "name": "Kotlin", 169 | "checked": false 170 | }, 171 | { 172 | "path": "livescript", 173 | "short_name": "LS", 174 | "name": "LiveScript", 175 | "checked": false 176 | }, 177 | { 178 | "path": "lua", 179 | "name": "Lua", 180 | "checked": false 181 | }, 182 | { 183 | "path": "makefile", 184 | "name": "Makefile", 185 | "checked": false 186 | }, 187 | { 188 | "path": "matlab", 189 | "name": "Matlab", 190 | "checked": false 191 | }, 192 | { 193 | "path": "nsis", 194 | "name": "NSIS", 195 | "checked": false 196 | }, 197 | { 198 | "path": "nimrod", 199 | "name": "Nimrod", 200 | "checked": false 201 | }, 202 | { 203 | "path": "ocaml", 204 | "name": "OCaml", 205 | "checked": false 206 | }, 207 | { 208 | "short_name": "Obj-C", 209 | "path": "objective-c", 210 | "name": "Objective-C", 211 | "checked": false 212 | }, 213 | { 214 | "short_name": "Obj-C++", 215 | "path": "objective-c%2B%2B", 216 | "name": "Objective-C++", 217 | "checked": false 218 | }, 219 | { 220 | "path": "php", 221 | "name": "PHP", 222 | "checked": false 223 | }, 224 | { 225 | "path": "plsql", 226 | "name": "PLSQL", 227 | "checked": false 228 | }, 229 | { 230 | "path": "pascal", 231 | "name": "Pascal", 232 | "checked": false 233 | }, 234 | { 235 | "path": "perl", 236 | "name": "Perl", 237 | "checked": false 238 | }, 239 | { 240 | "path": "postscript", 241 | "name": "PostScript", 242 | "checked": false 243 | }, 244 | { 245 | "path": "powershell", 246 | "name": "PowerShell", 247 | "checked": false 248 | }, 249 | { 250 | "path": "python", 251 | "name": "Python", 252 | "checked": false 253 | }, 254 | { 255 | "path": "qml", 256 | "name": "QML", 257 | "checked": false 258 | }, 259 | { 260 | "path": "r", 261 | "name": "R", 262 | "checked": false 263 | }, 264 | { 265 | "path": "ruby", 266 | "name": "Ruby", 267 | "checked": false 268 | }, 269 | { 270 | "path": "rust", 271 | "name": "Rust", 272 | "checked": false 273 | }, 274 | { 275 | "path": "scala", 276 | "name": "Scala", 277 | "checked": false 278 | }, 279 | { 280 | "path": "scheme", 281 | "name": "Scheme", 282 | "checked": false 283 | }, 284 | { 285 | "path": "bash", 286 | "name": "Shell", 287 | "checked": false 288 | }, 289 | { 290 | "path": "supercollider", 291 | "name": "SuperCollider", 292 | "checked": false 293 | }, 294 | { 295 | "path": "swift", 296 | "name": "Swift", 297 | "checked": false 298 | }, 299 | { 300 | "path": "tex", 301 | "name": "TeX", 302 | "checked": false 303 | }, 304 | { 305 | "path": "typescript", 306 | "name": "TypeScript", 307 | "checked": false 308 | }, 309 | { 310 | "path": "verilog", 311 | "name": "Verilog", 312 | "checked": false 313 | }, 314 | { 315 | "path": "xslt", 316 | "name": "XSLT", 317 | "checked": false 318 | } 319 | ] -------------------------------------------------------------------------------- /js/common/NavigationBar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * NavigationBar 3 | * @flow 4 | */ 5 | import React, {Component, PropTypes} from 'react'; 6 | 7 | import { 8 | StyleSheet, 9 | Navigator, 10 | Platform, 11 | TouchableOpacity, 12 | Image, 13 | StatusBar, 14 | Text, 15 | View 16 | } from 'react-native' 17 | import GlobalStyles from '../../res/styles/GlobalStyles' 18 | const NAV_BAR_HEIGHT_IOS = GlobalStyles.nav_bar_height_ios; 19 | const NAV_BAR_HEIGHT_ANDROID = GlobalStyles.nav_bar_height_android; 20 | const STATUS_BAR_HEIGHT = 20; 21 | 22 | const ButtonShape = { 23 | title: PropTypes.string.isRequired, 24 | style: PropTypes.any, 25 | handler: PropTypes.func, 26 | }; 27 | const StatusBarShape = { 28 | barStyle: PropTypes.oneOf(['light-content', 'default',]), 29 | networkActivityIndicatorVisible: PropTypes.bool, 30 | showHideTransition:PropTypes.oneOf(['fade', 'slide']), 31 | hidden: PropTypes.bool, 32 | translucent: PropTypes.bool, 33 | backgroundColor: PropTypes.string, 34 | animated:PropTypes.bool 35 | }; 36 | 37 | export default class NavigationBar extends Component { 38 | static propTypes = { 39 | style: View.propTypes.style, 40 | titleLayoutStyle:View.propTypes.style, 41 | navigator: PropTypes.object, 42 | leftButtonTitle: PropTypes.string, 43 | popEnabled: PropTypes.bool, 44 | onLeftButtonClick: PropTypes.func, 45 | title: PropTypes.string, 46 | titleView: PropTypes.element, 47 | hide: PropTypes.bool, 48 | statusBar: PropTypes.shape(StatusBarShape), 49 | rightButton: PropTypes.oneOfType([ 50 | PropTypes.shape(ButtonShape), 51 | PropTypes.element, 52 | ]), 53 | leftButton: PropTypes.oneOfType([ 54 | PropTypes.shape(ButtonShape), 55 | PropTypes.element, 56 | ]), 57 | 58 | } 59 | static defaultProps = { 60 | statusBar: { 61 | barStyle: 'default', 62 | hidden: false, 63 | translucent:false, 64 | animated:false, 65 | }, 66 | } 67 | 68 | constructor(props) { 69 | super(props); 70 | this.state = { 71 | title: '', 72 | popEnabled: true, 73 | hide: false 74 | }; 75 | } 76 | leftView() { 77 | var leftView = this.props.leftButtonTitle ? 78 | {this.props.leftButtonTitle} : null; 79 | return ( 80 | this.onLeftButtonClick()}> 82 | 83 | {this.props.leftView ? this.props.leftView : leftView} 84 | 85 | 86 | ) 87 | } 88 | 89 | onLeftButtonClick() { 90 | if (this.props.navigator && this.props.popEnabled)this.props.navigator.pop(); 91 | if (this.props.onLeftButtonClick)this.props.onLeftButtonClick(); 92 | } 93 | 94 | getButtonElement(data = {}, style) { 95 | return ( 96 | 97 | {(!!data.props) ? data : ( 98 | 103 | )} 104 | 105 | ); 106 | } 107 | 108 | render() { 109 | let statusBar = !this.props.statusBar.hidden ? 110 | 111 | 112 | : null; 113 | 114 | let titleView = this.props.titleView ? this.props.titleView : 115 | {this.props.title}; 116 | 117 | let content = this.props.hide ? null : 118 | 119 | {/*{this.leftView()}*/} 120 | {this.getButtonElement(this.props.leftButton)} 121 | 122 | {titleView} 123 | 124 | {/*{this.rightView()}*/} 125 | {this.getButtonElement(this.props.rightButton, {marginRight: 8,})} 126 | ; 127 | return ( 128 | 129 | {statusBar} 130 | {content} 131 | 132 | ) 133 | } 134 | } 135 | class NavBarButton extends Component { 136 | render() { 137 | const {style, tintColor, margin, title, handler} = this.props; 138 | 139 | return ( 140 | 141 | 142 | {title} 143 | 144 | 145 | ); 146 | } 147 | 148 | static propTypes = { 149 | style: PropTypes.oneOfType([ 150 | PropTypes.object, 151 | PropTypes.array, 152 | ]), 153 | tintColor: PropTypes.string, 154 | title: PropTypes.string, 155 | handler: PropTypes.func, 156 | }; 157 | 158 | static defaultProps = { 159 | style: {}, 160 | title: '', 161 | tintColor: '#0076FF', 162 | onPress: () => ({}), 163 | }; 164 | } 165 | 166 | const styles = StyleSheet.create({ 167 | container: { 168 | backgroundColor: '#4caf50', 169 | }, 170 | navBar: { 171 | flexDirection: 'row', 172 | alignItems: 'center', 173 | justifyContent: 'space-between', 174 | // backgroundColor: 'red', 175 | height: Platform.OS === 'ios' ? NAV_BAR_HEIGHT_IOS : NAV_BAR_HEIGHT_ANDROID, 176 | // shadowOffset:{ 177 | // width: 1, 178 | // height: 0.5, 179 | // }, 180 | // shadowColor: '#55ACEE', 181 | // shadowOpacity: 0.8, 182 | }, 183 | navBarTitleContainer: { 184 | alignItems: 'center', 185 | justifyContent: 'center', 186 | position: 'absolute', 187 | left: 40, 188 | top: 0, 189 | right: 40, 190 | bottom: 0, 191 | }, 192 | title: { 193 | fontSize: 20, 194 | color: '#FFFFFF', 195 | // backgroundColor:'blue', 196 | }, 197 | navBarButton: { 198 | alignItems: 'center', 199 | }, 200 | statusBar: { 201 | height: Platform.OS === 'ios' ? STATUS_BAR_HEIGHT:0, 202 | 203 | }, 204 | }) 205 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | 3 | import com.android.build.OutputFile 4 | 5 | /** 6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets 7 | * and bundleReleaseJsAndAssets). 8 | * These basically call `react-native bundle` with the correct arguments during the Android build 9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the 10 | * bundle directly from the development server. Below you can see all the possible configurations 11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the 12 | * `apply from: "../../node_modules/react-native/react.gradle"` line. 13 | * 14 | * project.ext.react = [ 15 | * // the name of the generated asset file containing your JS bundle 16 | * bundleAssetName: "index.android.bundle", 17 | * 18 | * // the entry file for bundle generation 19 | * entryFile: "index.android.js", 20 | * 21 | * // whether to bundle JS and assets in debug mode 22 | * bundleInDebug: false, 23 | * 24 | * // whether to bundle JS and assets in release mode 25 | * bundleInRelease: true, 26 | * 27 | * // whether to bundle JS and assets in another build variant (if configured). 28 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants 29 | * // The configuration property can be in the following formats 30 | * // 'bundleIn${productFlavor}${buildType}' 31 | * // 'bundleIn${buildType}' 32 | * // bundleInFreeDebug: true, 33 | * // bundleInPaidRelease: true, 34 | * // bundleInBeta: true, 35 | * 36 | * // the root of your project, i.e. where "package.json" lives 37 | * root: "../../", 38 | * 39 | * // where to put the JS bundle asset in debug mode 40 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", 41 | * 42 | * // where to put the JS bundle asset in release mode 43 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release", 44 | * 45 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 46 | * // require('./image.png')), in debug mode 47 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", 48 | * 49 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 50 | * // require('./image.png')), in release mode 51 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", 52 | * 53 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means 54 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to 55 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle 56 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ 57 | * // for example, you might want to remove it from here. 58 | * inputExcludes: ["android/**", "ios/**"], 59 | * 60 | * // override which node gets called and with what additional arguments 61 | * nodeExecutableAndArgs: ["node"] 62 | * 63 | * // supply additional arguments to the packager 64 | * extraPackagerArgs: [] 65 | * ] 66 | */ 67 | 68 | apply from: "../../node_modules/react-native/react.gradle" 69 | 70 | /** 71 | * Set this to true to create two separate APKs instead of one: 72 | * - An APK that only works on ARM devices 73 | * - An APK that only works on x86 devices 74 | * The advantage is the size of the APK is reduced by about 4MB. 75 | * Upload all the APKs to the Play Store and people will download 76 | * the correct one based on the CPU architecture of their device. 77 | */ 78 | def enableSeparateBuildPerCPUArchitecture = false 79 | 80 | /** 81 | * Run Proguard to shrink the Java bytecode in release builds. 82 | */ 83 | def enableProguardInReleaseBuilds = true 84 | //从Keychain Access中获取证书密码 85 | def getPassword(String currentUser, String keyChain) { 86 | def stdout = new ByteArrayOutputStream() 87 | def stderr = new ByteArrayOutputStream() 88 | exec { 89 | commandLine 'security', '-q', 'find-generic-password', '-a', currentUser, '-s', keyChain, '-w' 90 | standardOutput = stdout 91 | errorOutput = stderr 92 | ignoreExitValue true 93 | } 94 | //noinspection GroovyAssignabilityCheck 95 | stdout.toString().trim() 96 | } 97 | def pass = getPassword("jph","jph_android_keystore") 98 | 99 | 100 | android { 101 | compileSdkVersion 23 102 | buildToolsVersion "23.0.1" 103 | 104 | defaultConfig { 105 | applicationId "com.jph.githubpopular" 106 | minSdkVersion 16 107 | targetSdkVersion 23 108 | versionCode 1 109 | versionName "1.0" 110 | ndk { 111 | abiFilters "armeabi-v7a", "x86" 112 | } 113 | } 114 | 115 | signingConfigs {//签名配置 116 | release { 117 | storeFile file(MYAPP_RELEASE_STORE_FILE) 118 | storePassword pass 119 | keyAlias MYAPP_RELEASE_KEY_ALIAS 120 | keyPassword pass 121 | } 122 | } 123 | 124 | splits { 125 | abi { 126 | reset() 127 | enable enableSeparateBuildPerCPUArchitecture 128 | universalApk false // If true, also generate a universal APK 129 | include "armeabi-v7a", "x86" 130 | } 131 | } 132 | buildTypes { 133 | release { 134 | minifyEnabled enableProguardInReleaseBuilds 135 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 136 | signingConfig signingConfigs.release 137 | } 138 | } 139 | // applicationVariants are e.g debug, release 140 | applicationVariants.all { variant -> 141 | variant.outputs.each { output -> 142 | // For each separate APK per architecture, set a unique version code as described here: 143 | // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits 144 | def versionCodes = ["armeabi-v7a":1, "x86":2] 145 | def abi = output.getFilter(OutputFile.ABI) 146 | if (abi != null) { // null for the universal-debug, universal-release variants 147 | output.versionCodeOverride = 148 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode 149 | } 150 | } 151 | } 152 | } 153 | 154 | dependencies { 155 | compile project(':react-native-splash-screen') 156 | compile fileTree(dir: 'libs', include: ['*.jar']) 157 | compile 'com.android.support:appcompat-v7:23.0.1' 158 | compile 'com.facebook.react:react-native:+' 159 | } 160 | 161 | // Run this once to be able to run the application with BUCK 162 | // puts all compile dependencies into folder libs for BUCK to use 163 | task copyDownloadableDepsToLibs(type: Copy) { 164 | from configurations.compile 165 | into 'libs' 166 | } 167 | -------------------------------------------------------------------------------- /js/page/about/AboutCommon.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AboutPage 3 | * 关于 4 | * @flow 5 | */ 6 | 'use strict'; 7 | 8 | 9 | import React, {Component} from 'react'; 10 | import { 11 | Dimensions, 12 | Image, 13 | ListView, 14 | Platform, 15 | PixelRatio, 16 | StyleSheet, 17 | Text, 18 | View, 19 | } from 'react-native'; 20 | 21 | import ParallaxScrollView from 'react-native-parallax-scroll-view'; 22 | import RepositoryCell from '../../common/RepositoryCell'; 23 | import BaseCommon from '../../common/BaseCommon' 24 | import RepositoryDetail from '../../page/RepositoryDetail'; 25 | import FavoriteDao from '../../expand/dao/FavoriteDao' 26 | import {FLAG_STORAGE} from '../../expand/dao/DataRepository' 27 | import Utils from '../../util/Utils' 28 | import GlobalStyles from '../../../res/styles/GlobalStyles' 29 | import ViewUtils from '../../util/ViewUtils' 30 | 31 | export default class AboutCommon { 32 | constructor(props, updateState) { 33 | this.props = props; 34 | this.baseCommon=new BaseCommon({...props,backPress:(e)=>this.onBackPress(e)}); 35 | this.updateState = updateState; 36 | this.favoriteDao = new FavoriteDao(FLAG_STORAGE.flag_popular); 37 | } 38 | onBackPress(e){ 39 | this.props.navigator.pop(); 40 | return true; 41 | } 42 | componentDidMount() { 43 | this.baseCommon.componentDidMount(); 44 | } 45 | componentWillUnmount() { 46 | this.baseCommon.componentWillUnmount(); 47 | } 48 | async updateFavorite(repositories) { 49 | if (repositories)this.repositories = repositories; 50 | if(!this.repositories)return; 51 | let favoriteKeys = await this.favoriteDao.getFavoriteKeys(); 52 | if(!favoriteKeys)favoriteKeys=[]; 53 | let projectModels = []; 54 | for (let i = 0, l = this.repositories.length; i < l; i++) { 55 | projectModels.push({ 56 | isFavorite: Utils.checkFavorite(this.repositories[i], favoriteKeys), 57 | item: this.repositories[i], 58 | }) 59 | } 60 | this.updateState({ 61 | projectModels: projectModels, 62 | }) 63 | } 64 | 65 | onFavorite(item, isFavorite) {//favoriteIcon单击回调函数 66 | if (isFavorite) { 67 | this.favoriteDao.saveFavoriteItem(item.id.toString(), JSON.stringify(item)); 68 | } else { 69 | this.favoriteDao.removeFavoriteItem(item.id.toString()); 70 | } 71 | } 72 | 73 | onSelectRepository(projectModel) { 74 | var item = projectModel.item; 75 | this.props.navigator.push({ 76 | title: item.full_name, 77 | component: RepositoryDetail, 78 | params: { 79 | projectModel: projectModel, 80 | parentComponent: this, 81 | ...this.props, 82 | flag: FLAG_STORAGE.flag_popular, 83 | }, 84 | }); 85 | } 86 | 87 | renderRepository(projectModels) { 88 | if (!projectModels)return null; 89 | let views = []; 90 | for (let i = 0, l = projectModels.length; ithis.onSelectRepository(projectModel)} 96 | theme={this.props.theme} 97 | projectModel={projectModel} 98 | onFavorite={(item, isFavorite)=>this.onFavorite(item, isFavorite)}/> 99 | ); 100 | } 101 | return views; 102 | } 103 | 104 | getParallaxRenderConfig(params) { 105 | let config = {}; 106 | let avatar=typeof(params.avatar)==='string' ? {uri:params.avatar}:params.avatar; 107 | config.renderBackground = () => ( 108 | 109 | 114 | 121 | 122 | ); 123 | config.renderForeground = () => ( 124 | 125 | 126 | 127 | {params.name} 128 | 129 | 130 | {params.description} 131 | 132 | 133 | ); 134 | config.renderStickyHeader = () => ( 135 | 136 | {params.name} 137 | 138 | ); 139 | config.renderFixedHeader = () => ( 140 | 141 | {ViewUtils.getLeftButton(()=>this.props.navigator.pop())} 142 | 144 | 145 | 146 | ); 147 | return config; 148 | } 149 | 150 | render(contentView,params) { 151 | let renderConfig = this.getParallaxRenderConfig(params); 152 | return ( 153 | 162 | {contentView} 163 | 164 | ); 165 | } 166 | } 167 | 168 | const window = Dimensions.get('window'); 169 | 170 | const AVATAR_SIZE = 90; 171 | const PARALLAX_HEADER_HEIGHT = 270; 172 | const STICKY_HEADER_HEIGHT =(Platform.OS === 'ios') ? GlobalStyles.nav_bar_height_ios+20:GlobalStyles.nav_bar_height_android; 173 | 174 | const styles = StyleSheet.create({ 175 | container: { 176 | flex: 1, 177 | backgroundColor: 'black' 178 | }, 179 | stickySection: { 180 | height: STICKY_HEADER_HEIGHT, 181 | justifyContent: 'center', 182 | paddingTop: (Platform.OS === 'ios') ? 20:0, 183 | alignItems: 'center', 184 | }, 185 | stickySectionText: { 186 | color: 'white', 187 | fontSize: 20, 188 | margin: 10 189 | }, 190 | fixedSection: { 191 | position: 'absolute', 192 | left: 0, 193 | right: 0, 194 | top: 0, 195 | bottom: 0, 196 | paddingRight: 8, 197 | paddingTop: (Platform.OS === 'ios') ? 20:0, 198 | flexDirection: 'row', 199 | alignItems: 'center', 200 | justifyContent: 'space-between', 201 | }, 202 | fixedSectionText: { 203 | color: 'white', 204 | fontSize: 20, 205 | opacity: .9, 206 | }, 207 | parallaxHeader: { 208 | alignItems: 'center', 209 | flex: 1, 210 | flexDirection: 'column', 211 | paddingTop: 60 212 | }, 213 | avatar: { 214 | width: AVATAR_SIZE, 215 | height: AVATAR_SIZE, 216 | marginBottom: 5, 217 | borderRadius: AVATAR_SIZE / 2 218 | }, 219 | sectionSpeakerText: { 220 | color: 'white', 221 | fontSize: 24, 222 | paddingVertical: 5 223 | }, 224 | sectionTitleText: { 225 | color: 'white', 226 | fontSize: 16, 227 | marginLeft: 10, 228 | marginRight: 10, 229 | }, 230 | }); 231 | -------------------------------------------------------------------------------- /js/page/about/AboutMePage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AboutMePage 3 | * 关于 4 | * @flow 5 | */ 6 | 'use strict'; 7 | 8 | 9 | import React, {Component} from 'react'; 10 | import { 11 | Image, 12 | StyleSheet, 13 | View, 14 | Text, 15 | Linking, 16 | Clipboard, 17 | } from 'react-native'; 18 | 19 | import WebViewPage from '../../page/WebViewPage'; 20 | import RepositoryUtils from '../../expand/dao/RepositoryUtils'; 21 | import ViewUtils from '../../util/ViewUtils' 22 | import GlobalStyles from '../../../res/styles/GlobalStyles' 23 | import AboutCommon from './AboutCommon' 24 | import config from '../../../res/data/Config.json' 25 | import Toast from 'react-native-easy-toast' 26 | const FLAG = { 27 | REPOSITORY: '开源项目', 28 | BLOG: { 29 | name: '技术博客', 30 | items: { 31 | PERSONAL_BLOG: { 32 | title: '个人博客', 33 | url: 'http://jiapenghui.com', 34 | }, 35 | CSDN: { 36 | title: 'CSDN', 37 | url: 'http://blog.csdn.net/fengyuzhengfan', 38 | }, 39 | JIANSHU: { 40 | title: '简书', 41 | url: 'http://www.jianshu.com/users/ca3943a4172a/latest_articles', 42 | }, 43 | GITHUB: { 44 | title: 'GitHub', 45 | url: 'https://github.com/crazycodeboy', 46 | }, 47 | } 48 | }, 49 | CONTACT: { 50 | name: '联系方式', 51 | items: { 52 | QQ: { 53 | title: 'QQ', 54 | account: '1586866509', 55 | }, 56 | Email: { 57 | title: 'Email', 58 | account: 'crazycodeboy@gmail.com', 59 | }, 60 | } 61 | }, 62 | QQ: { 63 | name: '技术交流群', 64 | items: { 65 | MD: { 66 | title: '移动开发者技术分享群', 67 | account: '335939197', 68 | }, 69 | RN: { 70 | title: 'React Native学习交流群', 71 | account: '165774887', 72 | } 73 | }, 74 | }, 75 | 76 | }; 77 | 78 | export default class AboutMePage extends Component { 79 | constructor(props) { 80 | super(props); 81 | this.aboutCommon = new AboutCommon(props, (dic)=>this.updateState(dic)); 82 | this.repositories = []; 83 | this.state = { 84 | projectModels: null, 85 | author: {}, 86 | showRepository: false, 87 | showBlog: false, 88 | showQQ: false, 89 | showContact: false, 90 | 91 | } 92 | } 93 | 94 | componentDidMount() { 95 | this.initRepository(); 96 | this.getConfig(); 97 | this.aboutCommon.componentDidMount(); 98 | } 99 | componentWillUnmount(){ 100 | this.aboutCommon.componentWillUnmount(); 101 | } 102 | async getConfig() { 103 | let data = await RepositoryUtils.init().getConfig(); 104 | if (!data)data = config; 105 | this.setState({ 106 | author: data.author, 107 | }) 108 | } 109 | 110 | async initRepository() { 111 | this.repositories = await RepositoryUtils.init().fetchRepositories(); 112 | this.aboutCommon.updateFavorite(this.repositories); 113 | } 114 | 115 | updateState(dic) { 116 | this.setState(dic); 117 | } 118 | 119 | onClick(tab) { 120 | let TargetComponent, params = {...this.props, menuType: tab}; 121 | switch (tab) { 122 | case FLAG.CONTACT.items.Email: 123 | Linking.openURL('mailto:'+tab.account); 124 | break; 125 | case FLAG.CONTACT.items.QQ: 126 | this.toast.show('QQ:' + tab.account + '已复制到剪切板。'); 127 | Clipboard.setString(tab.account); 128 | break; 129 | case FLAG.QQ.items.MD: 130 | case FLAG.QQ.items.RN: 131 | this.toast.show('群号:' + tab.account + '已复制到剪切板。'); 132 | Clipboard.setString(tab.account); 133 | break; 134 | case FLAG.BLOG.items.CSDN: 135 | case FLAG.BLOG.items.GITHUB: 136 | case FLAG.BLOG.items.JIANSHU: 137 | case FLAG.BLOG.items.PERSONAL_BLOG: 138 | TargetComponent = WebViewPage; 139 | params.title = tab.title; 140 | params.url = tab.url; 141 | break; 142 | case FLAG.REPOSITORY: 143 | this.updateState({showRepository: !this.state.showRepository}); 144 | break; 145 | case FLAG.BLOG: 146 | this.updateState({showBlog: !this.state.showBlog}); 147 | break; 148 | case FLAG.QQ: 149 | this.updateState({showQQ: !this.state.showQQ}); 150 | break; 151 | case FLAG.CONTACT: 152 | this.updateState({showContact: !this.state.showContact}); 153 | break; 154 | 155 | } 156 | if (TargetComponent) { 157 | this.props.navigator.push({ 158 | component: TargetComponent, 159 | params: params, 160 | }); 161 | } 162 | } 163 | 164 | renderItems(dic, isShowAccount) { 165 | if (!dic)return null; 166 | let views = []; 167 | for (let i in dic) { 168 | let title = isShowAccount ? dic[i].title + ':' + dic[i].account : dic[i].title; 169 | views.push( 170 | 171 | {ViewUtils.getSettingItem(()=>this.onClick(dic[i]), '', title, this.props.theme.styles.tabBarSelectedIcon)} 172 | 173 | 174 | ); 175 | } 176 | return views; 177 | } 178 | 179 | getClickIcon(isShow) { 180 | return isShow ? require('../../../res/images/ic_tiaozhuan_up.png') : require('../../../res/images/ic_tiaozhuan_down.png'); 181 | } 182 | 183 | render() { 184 | let content = 185 | {ViewUtils.getSettingItem(()=>this.onClick(FLAG.BLOG), require('../../../res/images/ic_computer.png'), 186 | FLAG.BLOG.name, this.props.theme.styles.tabBarSelectedIcon, this.getClickIcon(this.state.showBlog))} 187 | 188 | {this.state.showBlog ? this.renderItems(FLAG.BLOG.items) : null} 189 | 190 | {ViewUtils.getSettingItem(()=>this.onClick(FLAG.REPOSITORY), require('../../../res/images/ic_code.png'), 191 | FLAG.REPOSITORY, this.props.theme.styles.tabBarSelectedIcon, this.getClickIcon(this.state.showRepository))} 192 | 193 | {this.state.showRepository ? this.aboutCommon.renderRepository(this.state.projectModels) : null} 194 | 195 | {ViewUtils.getSettingItem(()=>this.onClick(FLAG.QQ), require('../../../res/images/ic_computer.png'), 196 | FLAG.QQ.name, this.props.theme.styles.tabBarSelectedIcon, this.getClickIcon(this.state.showQQ))} 197 | 198 | {this.state.showQQ ? this.renderItems(FLAG.QQ.items, true) : null} 199 | 200 | {ViewUtils.getSettingItem(()=>this.onClick(FLAG.CONTACT), require('../../../res/images/ic_contacts.png'), 201 | FLAG.CONTACT.name, this.props.theme.styles.tabBarSelectedIcon, this.getClickIcon(this.state.showContact))} 202 | 203 | {this.state.showContact ? this.renderItems(FLAG.CONTACT.items, true) : null} 204 | 205 | return ( 206 | 207 | {this.aboutCommon.render(content, this.state.author)} 208 | this.toast = e}/> 209 | ); 210 | } 211 | } 212 | const styles = StyleSheet.create({ 213 | container: { 214 | flex: 1, 215 | }, 216 | contactItemLayout: { 217 | flexDirection: 'row', alignItems: 'center' 218 | }, 219 | contactContentText: { 220 | color: 'dodgerblue', fontSize: 13, textDecorationLine: 'underline' 221 | }, 222 | contactName: { 223 | fontSize: 13, color: 'gray', fontWeight: '400' 224 | }, 225 | }); 226 | -------------------------------------------------------------------------------- /js/page/my/MyPage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 我的页面 3 | * @flow 4 | * **/ 5 | import React, {Component} from "react"; 6 | import { 7 | StyleSheet, 8 | View, 9 | Image, 10 | Modal, 11 | Text, 12 | Platform, 13 | ScrollView, 14 | TouchableHighlight 15 | } from "react-native"; 16 | import NavigationBar from "../../common/NavigationBar"; 17 | import {MORE_MENU} from "../../common/MoreMenu"; 18 | import CustomKeyPage from "./CustomKeyPage"; 19 | import SortKeyPagePage from "./SortKeyPagePage"; 20 | import CustomThemePage from "./CustomTheme"; 21 | import AboutPage from '../about/AboutPage' 22 | import AboutMePage from '../about/AboutMePage' 23 | import {FLAG_LANGUAGE} from "../../expand/dao/LanguageDao"; 24 | import ThemeDao from "../../expand/dao/ThemeDao"; 25 | import GlobalStyles from '../../../res/styles/GlobalStyles' 26 | import ViewUtils from '../../util/ViewUtils' 27 | 28 | export default class MyPage extends Component { 29 | 30 | constructor(props) { 31 | super(props); 32 | this.themeDao = new ThemeDao(); 33 | this.state = { 34 | customThemeViewVisible: false, 35 | theme: this.props.theme, 36 | } 37 | } 38 | 39 | componentDidMount() { 40 | this.props.homeComponent.addSubscriber(this.onSubscriber); 41 | } 42 | 43 | componentWillUnmount() { 44 | this.props.homeComponent.removeSubscriber(this.onSubscriber); 45 | } 46 | 47 | onSubscriber = (preTab, currentTab)=> { 48 | var changedValues = this.props.homeComponent.changedValues; 49 | if (changedValues.my.themeChange && preTab.styles) { 50 | this.setState({ 51 | theme: preTab 52 | }) 53 | return; 54 | } 55 | } 56 | 57 | onClick(tab) { 58 | let TargetComponent, params = {...this.props, theme: this.state.theme, menuType: tab}; 59 | switch (tab) { 60 | case MORE_MENU.Custom_Language: 61 | TargetComponent = CustomKeyPage; 62 | params.flag = FLAG_LANGUAGE.flag_language; 63 | break; 64 | case MORE_MENU.Custom_Key: 65 | TargetComponent = CustomKeyPage; 66 | params.flag = FLAG_LANGUAGE.flag_key; 67 | break; 68 | case MORE_MENU.Remove_Key: 69 | TargetComponent = CustomKeyPage; 70 | params.flag = FLAG_LANGUAGE.flag_key; 71 | break; 72 | case MORE_MENU.Sort_Language: 73 | TargetComponent = SortKeyPagePage; 74 | params.flag = FLAG_LANGUAGE.flag_language; 75 | break; 76 | case MORE_MENU.Sort_Key: 77 | TargetComponent = SortKeyPagePage; 78 | params.flag = FLAG_LANGUAGE.flag_key; 79 | break; 80 | case MORE_MENU.Custom_Theme: 81 | this.setState({customThemeViewVisible: true}); 82 | break; 83 | case MORE_MENU.About_Author: 84 | TargetComponent = AboutMePage; 85 | break; 86 | case MORE_MENU.About: 87 | TargetComponent =AboutPage; 88 | break; 89 | 90 | } 91 | if (TargetComponent) { 92 | this.props.navigator.push({ 93 | component: TargetComponent, 94 | params: params, 95 | }); 96 | } 97 | } 98 | 99 | getItem(tag, icon, text) { 100 | return ViewUtils.getSettingItem(()=>this.onClick(tag), icon, text, this.state.theme.styles.tabBarSelectedIcon); 101 | } 102 | 103 | renderCustomThemeView() { 104 | return ( 105 | { 109 | this.setState({customThemeViewVisible: false}) 110 | }}/> 111 | ) 112 | } 113 | 114 | render() { 115 | var navigationBar = 116 | ; 119 | return ( 120 | 121 | {navigationBar} 122 | 123 | {/*logo*/} 124 | this.onClick(MORE_MENU.About)}> 126 | 127 | 128 | 130 | GitHub Popular 131 | 132 | 140 | 141 | 142 | 143 | 144 | {/*Custom trending language*/} 145 | Custom trending language 146 | {/*Custom Language*/} 147 | 148 | {this.getItem(MORE_MENU.Custom_Language, require('./img/ic_custom_language.png'), 'Custom Language')} 149 | {/*Sort language*/} 150 | 151 | {this.getItem(MORE_MENU.Sort_Language, require('./img/ic_swap_vert.png'), 'Sort language')} 152 | 153 | {/*Custom popular key*/} 154 | Custom popular key 155 | {/*custom Key*/} 156 | 157 | {this.getItem(MORE_MENU.Custom_Key, require('./img/ic_custom_language.png'), 'Custom Key')} 158 | {/*Sort Key*/} 159 | 160 | {this.getItem(MORE_MENU.Sort_Key, require('./img/ic_swap_vert.png'), 'Sort Key')} 161 | {/*Remove Key*/} 162 | 163 | {this.getItem(MORE_MENU.Remove_Key, require('./img/ic_remove.png'), 'Remove Key')} 164 | 165 | {/*Setting*/} 166 | Setting 167 | {/*Custom theme*/} 168 | 169 | {this.getItem(MORE_MENU.Custom_Theme, require('./img/ic_view_quilt.png'), 'Custom theme')} 170 | {/*Night mode*/} 171 | 172 | {this.getItem('about', require('./img/ic_brightness.png'), 'Night mode')} 173 | {/*About author*/} 174 | 175 | {this.getItem(MORE_MENU.About_Author, require('./img/ic_insert_emoticon.png'), 'About author')} 176 | 177 | 178 | {this.renderCustomThemeView()} 179 | 180 | ); 181 | } 182 | 183 | } 184 | const styles = StyleSheet.create({ 185 | item: { 186 | backgroundColor: 'white', 187 | padding: 10, height: 60, 188 | alignItems: 'center', 189 | justifyContent: 'space-between', 190 | flexDirection: 'row' 191 | }, 192 | groupTitle: { 193 | // fontWeight:'500', 194 | marginLeft: 10, 195 | marginTop: 10, 196 | marginBottom: 5, 197 | fontSize: 12, 198 | color: 'gray' 199 | 200 | }, 201 | }) -------------------------------------------------------------------------------- /js/page/FavoritePage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * FavoritePage 3 | * @flow 4 | */ 5 | 'use strict'; 6 | import React, {Component} from 'react' 7 | import { 8 | ListView, 9 | Platform, 10 | StyleSheet, 11 | TouchableHighlight, 12 | Image, 13 | RefreshControl, 14 | View, 15 | } from 'react-native' 16 | 17 | import ScrollableTabView, {ScrollableTabBar} from 'react-native-scrollable-tab-view' 18 | import ViewUtils from '../util/ViewUtils' 19 | import RepositoryCell from '../common/RepositoryCell' 20 | import TrendingRepoCell from '../common/TrendingRepoCell' 21 | import RepositoryDetail from './RepositoryDetail' 22 | import MoreMenu,{MORE_MENU} from '../common/MoreMenu' 23 | import {FLAG_TAB} from './HomePage' 24 | import CustomTheme from "./my/CustomTheme" 25 | import FavoriteDao from '../expand/dao/FavoriteDao' 26 | import ProjectModel from '../model/ProjectModel' 27 | import NavigationBar from '../common/NavigationBar' 28 | import {FLAG_STORAGE} from '../expand/dao/RepositoryDao' 29 | import ArrayUtils from '../util/ArrayUtils' 30 | import GlobalStyles from '../../res/styles/GlobalStyles' 31 | 32 | export default class FavoritePage extends Component { 33 | constructor(props) { 34 | super(props); 35 | this.state = { 36 | theme:this.props.theme, 37 | customThemeViewVisible:false, 38 | } 39 | } 40 | componentDidMount() { 41 | this.props.homeComponent.addSubscriber(this.onSubscriber); 42 | } 43 | 44 | componentWillUnmount() { 45 | this.props.homeComponent.removeSubscriber(this.onSubscriber); 46 | } 47 | onSubscriber = (preTab, currentTab)=> { 48 | var changedValues = this.props.homeComponent.changedValues; 49 | if(changedValues.my.themeChange&&preTab.styles) { 50 | this.setState({ 51 | theme:preTab 52 | }) 53 | return; 54 | } 55 | } 56 | renderMoreView() { 57 | let params = {...this.props, theme: this.state.theme,fromPage:FLAG_TAB.flag_favoriteTab} 58 | return { 64 | if(e==='Custom Theme'){ 65 | this.setState({customThemeViewVisible: true}); 66 | } 67 | }} 68 | anchorView={this} 69 | navigator={this.props.navigator} /> 70 | } 71 | render() { 72 | let content = 73 | } 82 | > 83 | 84 | 85 | 86 | let navigationBar = 87 | this.refs.moreMenu.open())} 90 | title='Favorite'/>; 91 | let customThemeView= 92 | {this.setState({customThemeViewVisible:false})}}/> 96 | return ( 97 | 98 | {navigationBar} 99 | {content} 100 | {customThemeView} 101 | {this.renderMoreView()} 102 | 103 | ); 104 | } 105 | 106 | } 107 | 108 | class FavoriteTab extends Component { 109 | constructor(props) { 110 | super(props); 111 | this.unFavoriteItems=[]; 112 | this.state = { 113 | isLoading: false, 114 | isLodingFail: false, 115 | dataSource: new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}), 116 | filter: '' 117 | }; 118 | } 119 | 120 | componentDidMount() { 121 | this.favoriteDao = new FavoriteDao(this.props.flag); 122 | this.loadData(true); 123 | } 124 | 125 | componentWillReceiveProps(nextProps) {//当从当前页面切换走,再切换回来后 126 | this.loadData(false); 127 | } 128 | 129 | loadData(isShowLoading) { 130 | if (isShowLoading) 131 | this.setState({ 132 | isLoading: true, 133 | isLodingFail: false, 134 | }); 135 | this.favoriteDao.getAllItems().then((items)=> { 136 | var resultData = []; 137 | for (var i = 0, len = items.length; i < len; i++) { 138 | resultData.push(new ProjectModel(items[i], true)); 139 | } 140 | this.setState({ 141 | isLoading: false, 142 | isLodingFail: false, 143 | dataSource: this.getDataSource(resultData), 144 | }); 145 | }).catch((error)=> { 146 | this.setState({ 147 | isLoading: false, 148 | isLodingFail: true, 149 | }); 150 | }); 151 | } 152 | 153 | onRefresh() { 154 | this.loadData(true); 155 | } 156 | 157 | getDataSource(items) { 158 | return this.state.dataSource.cloneWithRows(items); 159 | } 160 | 161 | onSelectRepository(projectModel) { 162 | var belongNavigator = this.props.navigator ? this.props.navigator : this.props.homeComponent.refs.navFavorite; 163 | var item = projectModel.item; 164 | belongNavigator.push({ 165 | title: item.full_name, 166 | component: RepositoryDetail, 167 | params: { 168 | projectModel: projectModel, 169 | flag:this.props.flag, 170 | ...this.props 171 | }, 172 | }); 173 | } 174 | 175 | onFavorite(item, isFavorite) { 176 | var key=this.props.flag===FLAG_STORAGE.flag_popular? item.id.toString():item.fullName; 177 | if (isFavorite) { 178 | this.favoriteDao.saveFavoriteItem(key, JSON.stringify(item)); 179 | } else { 180 | this.favoriteDao.removeFavoriteItem(key); 181 | } 182 | ArrayUtils.updateArray(this.unFavoriteItems,item); 183 | if(this.unFavoriteItems.length>0){ 184 | if (this.props.flag===FLAG_STORAGE.flag_popular){ 185 | this.props.homeComponent.changedValues.favorite.popularChange=true; 186 | }else { 187 | this.props.homeComponent.changedValues.favorite.trendingChange=true; 188 | } 189 | }else { 190 | if (this.props.flag===FLAG_STORAGE.flag_popular){ 191 | this.props.homeComponent.changedValues.favorite.popularChange=false; 192 | }else { 193 | this.props.homeComponent.changedValues.favorite.trendingChange=false; 194 | } 195 | } 196 | } 197 | 198 | renderRow(projectModel, sectionID, rowID) { 199 | let CellComponent=this.props.flag===FLAG_STORAGE.flag_popular? RepositoryCell:TrendingRepoCell; 200 | let {navigator}=this.props; 201 | return ( 202 | this.onFavorite(item, isFavorite)} 205 | isFavorite={true} 206 | {...{navigator}} 207 | theme={this.props.theme} 208 | onSelect={()=>this.onSelectRepository(projectModel)} 209 | projectModel={projectModel}/> 210 | ); 211 | } 212 | render() { 213 | var content = 214 | this.renderRow(e)} 218 | renderFooter={()=>{return }} 219 | enableEmptySections={true} 220 | dataSource={this.state.dataSource} 221 | refreshControl={ 222 | this.onRefresh()} 225 | tintColor={this.props.theme.themeColor} 226 | title="Loading..." 227 | titleColor={this.props.theme.themeColor} 228 | colors={[this.props.theme.themeColor, this.props.theme.themeColor, this.props.theme.themeColor]} 229 | />} 230 | />; 231 | return ( 232 | 233 | {content} 234 | 235 | ); 236 | } 237 | } 238 | 239 | var styles = StyleSheet.create({ 240 | container: { 241 | flex: 1, 242 | alignItems: 'stretch', 243 | // backgroundColor:'red' 244 | }, 245 | listView: { 246 | // marginTop: Platform.OS === "ios" ? 0 : 0, 247 | }, 248 | separator: { 249 | height: 1, 250 | backgroundColor: '#eeeeee', 251 | }, 252 | }); 253 | --------------------------------------------------------------------------------