├── settings.gradle ├── .idea └── copyright │ └── profiles_settings.xml ├── app ├── src │ ├── main │ │ ├── res │ │ │ ├── values-land │ │ │ │ └── dimens.xml │ │ │ ├── values-sw600dp-land │ │ │ │ └── dimens.xml │ │ │ ├── drawable │ │ │ │ ├── sad_astronaut.png │ │ │ │ ├── selector_circle_default.xml │ │ │ │ └── selector_default.xml │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── drawable-xhdpi │ │ │ │ ├── drawer_shadow.9.png │ │ │ │ ├── ic_info_white_24dp.png │ │ │ │ ├── ic_star_white_24dp.png │ │ │ │ ├── ic_favorite_white_24dp.png │ │ │ │ ├── ic_more_vert_white_24dp.png │ │ │ │ ├── ic_settings_white_24dp.png │ │ │ │ ├── ic_arrow_back_white_24dp.png │ │ │ │ ├── ic_filter_list_white_24dp.png │ │ │ │ ├── ic_fullscreen_white_24dp.png │ │ │ │ ├── ic_arrow_drop_up_white_18dp.png │ │ │ │ ├── ic_arrow_drop_down_white_18dp.png │ │ │ │ ├── ic_favorite_outline_white_24dp.png │ │ │ │ ├── ic_keyboard_arrow_up_white_24dp.png │ │ │ │ ├── ic_keyboard_arrow_down_white_24dp.png │ │ │ │ └── ic_keyboard_arrow_down_white_36dp.png │ │ │ ├── drawable-xxhdpi │ │ │ │ ├── drawer_shadow.9.png │ │ │ │ ├── ic_info_white_24dp.png │ │ │ │ ├── ic_star_white_24dp.png │ │ │ │ ├── ic_favorite_white_24dp.png │ │ │ │ ├── ic_settings_white_24dp.png │ │ │ │ ├── ic_arrow_back_white_24dp.png │ │ │ │ ├── ic_filter_list_white_24dp.png │ │ │ │ ├── ic_fullscreen_white_24dp.png │ │ │ │ ├── ic_more_vert_white_24dp.png │ │ │ │ ├── ic_arrow_drop_up_white_18dp.png │ │ │ │ ├── ic_arrow_drop_down_white_18dp.png │ │ │ │ ├── ic_favorite_outline_white_24dp.png │ │ │ │ ├── ic_keyboard_arrow_up_white_24dp.png │ │ │ │ ├── ic_keyboard_arrow_down_white_24dp.png │ │ │ │ └── ic_keyboard_arrow_down_white_36dp.png │ │ │ ├── drawable-hdpi │ │ │ │ ├── ic_info_white_24dp.png │ │ │ │ ├── ic_star_white_24dp.png │ │ │ │ ├── ic_favorite_white_24dp.png │ │ │ │ ├── ic_settings_white_24dp.png │ │ │ │ ├── ic_arrow_back_white_24dp.png │ │ │ │ ├── ic_fullscreen_white_24dp.png │ │ │ │ ├── ic_more_vert_white_24dp.png │ │ │ │ ├── ic_arrow_drop_up_white_18dp.png │ │ │ │ ├── ic_filter_list_white_24dp.png │ │ │ │ ├── ic_arrow_drop_down_white_18dp.png │ │ │ │ ├── ic_favorite_outline_white_24dp.png │ │ │ │ ├── ic_keyboard_arrow_up_white_24dp.png │ │ │ │ ├── ic_keyboard_arrow_down_white_24dp.png │ │ │ │ └── ic_keyboard_arrow_down_white_36dp.png │ │ │ ├── drawable-xxxhdpi │ │ │ │ ├── ic_info_white_24dp.png │ │ │ │ ├── ic_star_white_24dp.png │ │ │ │ ├── ic_arrow_back_white_24dp.png │ │ │ │ ├── ic_favorite_white_24dp.png │ │ │ │ ├── ic_fullscreen_white_24dp.png │ │ │ │ ├── ic_more_vert_white_24dp.png │ │ │ │ ├── ic_settings_white_24dp.png │ │ │ │ ├── ic_filter_list_white_24dp.png │ │ │ │ ├── ic_arrow_drop_down_white_18dp.png │ │ │ │ ├── ic_arrow_drop_up_white_18dp.png │ │ │ │ ├── ic_favorite_outline_white_24dp.png │ │ │ │ ├── ic_keyboard_arrow_up_white_24dp.png │ │ │ │ ├── ic_keyboard_arrow_down_white_24dp.png │ │ │ │ └── ic_keyboard_arrow_down_white_36dp.png │ │ │ ├── anim │ │ │ │ ├── decelerate_interpolator.xml │ │ │ │ ├── fade_in_shadow.xml │ │ │ │ ├── fade_out_shadow.xml │ │ │ │ ├── slide_in_left.xml │ │ │ │ ├── slide_out_right.xml │ │ │ │ ├── fade_in_right.xml │ │ │ │ ├── fade_out_right.xml │ │ │ │ └── zoom_in_exit.xml │ │ │ ├── drawable-v21 │ │ │ │ ├── selector_default.xml │ │ │ │ └── selector_circle_default.xml │ │ │ ├── layout │ │ │ │ ├── item_grid_header.xml │ │ │ │ ├── toolbar.xml │ │ │ │ ├── item_tile.xml │ │ │ │ ├── frag_main.xml │ │ │ │ ├── act_main.xml │ │ │ │ └── zero_state_list.xml │ │ │ ├── values-sw600dp │ │ │ │ └── dimens.xml │ │ │ ├── menu │ │ │ │ └── act_main.xml │ │ │ ├── values │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── attrs.xml │ │ │ │ ├── styles.xml │ │ │ │ └── strings.xml │ │ │ ├── layout-land │ │ │ │ └── zero_state_list.xml │ │ │ ├── values-de │ │ │ │ └── strings.xml │ │ │ └── values-fr │ │ │ │ └── strings.xml │ │ ├── assets │ │ │ └── fonts │ │ │ │ ├── Roboto-Black.ttf │ │ │ │ ├── Roboto-Bold.ttf │ │ │ │ ├── Roboto-Light.ttf │ │ │ │ ├── Roboto-Thin.ttf │ │ │ │ ├── Roboto-Italic.ttf │ │ │ │ ├── Roboto-Medium.ttf │ │ │ │ ├── Roboto-Regular.ttf │ │ │ │ ├── Roboto-BoldItalic.ttf │ │ │ │ ├── Roboto-ThinItalic.ttf │ │ │ │ ├── Roboto-BlackItalic.ttf │ │ │ │ ├── Roboto-LightItalic.ttf │ │ │ │ ├── Roboto-MediumItalic.ttf │ │ │ │ ├── RobotoCondensed-Bold.ttf │ │ │ │ ├── RobotoCondensed-Italic.ttf │ │ │ │ ├── RobotoCondensed-Light.ttf │ │ │ │ ├── RobotoCondensed-Regular.ttf │ │ │ │ ├── RobotoCondensed-BoldItalic.ttf │ │ │ │ └── RobotoCondensed-LightItalic.ttf │ │ ├── java │ │ │ └── com │ │ │ │ └── derek_s │ │ │ │ └── hubble_gallery │ │ │ │ ├── api │ │ │ │ ├── ApiClient.java │ │ │ │ ├── GetDetails.java │ │ │ │ └── GetAlbum.java │ │ │ │ ├── internal │ │ │ │ └── di │ │ │ │ │ ├── ActivityScope.java │ │ │ │ │ ├── ActivityComponent.java │ │ │ │ │ ├── AppComponent.java │ │ │ │ │ └── AppModule.java │ │ │ │ ├── base │ │ │ │ ├── Constants.java │ │ │ │ ├── ActBase.java │ │ │ │ ├── FragBase.java │ │ │ │ └── HubbleApplication.java │ │ │ │ ├── ui │ │ │ │ ├── widgets │ │ │ │ │ ├── SquareImageView.java │ │ │ │ │ ├── StretchyImageView.java │ │ │ │ │ ├── PopOutCircularProgressDrawable.java │ │ │ │ │ └── CircleProgressView.java │ │ │ │ ├── adapters │ │ │ │ │ ├── OnboardingFragmentPager.java │ │ │ │ │ ├── RecyclerViewItemClickListener.java │ │ │ │ │ └── MainGridAdapter.java │ │ │ │ ├── fragments │ │ │ │ │ ├── FragWelcomeOutline.java │ │ │ │ │ └── FragWelcomeInfo.java │ │ │ │ └── activities │ │ │ │ │ └── ActWelcome.java │ │ │ │ └── utils │ │ │ │ ├── ui │ │ │ │ ├── IndeterminateAnimator.java │ │ │ │ ├── Toasty.java │ │ │ │ ├── ToolbarTitle.java │ │ │ │ ├── starfield │ │ │ │ │ ├── Stars.java │ │ │ │ │ └── StarField.java │ │ │ │ └── FontFactory.java │ │ │ │ ├── FavoriteUtils.java │ │ │ │ ├── network │ │ │ │ └── NetworkUtil.java │ │ │ │ ├── ImageUtils.java │ │ │ │ ├── Animation │ │ │ │ └── SquareFlipper.java │ │ │ │ └── svg │ │ │ │ ├── SvgHelper.java │ │ │ │ └── SvgView.java │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── derek_s │ │ │ │ └── hubble_gallery │ │ │ │ ├── nav_drawer │ │ │ │ ├── dialog │ │ │ │ │ ├── DialogAboutListener.kt │ │ │ │ │ └── DialogAbout.kt │ │ │ │ ├── model │ │ │ │ │ ├── SectionObject.kt │ │ │ │ │ └── SectionChildObject.kt │ │ │ │ ├── views │ │ │ │ │ └── NavigationView.kt │ │ │ │ ├── adapters │ │ │ │ │ ├── NavigationAdapterItem.kt │ │ │ │ │ ├── SectionViewHolder.kt │ │ │ │ │ ├── NavDrawerAdapter.kt │ │ │ │ │ └── GroupViewHolder.kt │ │ │ │ └── presenters │ │ │ │ │ └── NavigationPresenter.kt │ │ │ │ ├── _shared │ │ │ │ └── model │ │ │ │ │ ├── Tiles.kt │ │ │ │ │ ├── TileObject.kt │ │ │ │ │ └── DetailsObject.kt │ │ │ │ ├── detailspage │ │ │ │ └── DetailsContract.java │ │ │ │ └── imageviewer │ │ │ │ └── ImageViewerActivity.java │ │ ├── res-details │ │ │ ├── layout │ │ │ │ ├── act_image_viewer.xml │ │ │ │ ├── zero_state_details.xml │ │ │ │ └── act_details.xml │ │ │ └── menu │ │ │ │ └── menu_act_details.xml │ │ ├── res-welcome │ │ │ └── layout │ │ │ │ ├── act_welcome.xml │ │ │ │ ├── frag_welcome_info.xml │ │ │ │ └── frag_welcome_outline.xml │ │ ├── res-navigation │ │ │ └── layout │ │ │ │ ├── frag_nav_drawer.xml │ │ │ │ ├── item_section.xml │ │ │ │ ├── item_group.xml │ │ │ │ ├── dialog_about.xml │ │ │ │ └── item_footer_nav_drawer.xml │ │ └── AndroidManifest.xml │ ├── debug │ │ ├── java │ │ │ └── com │ │ │ │ └── derek_s │ │ │ │ └── hubble_gallery │ │ │ │ └── base │ │ │ │ └── HubbleApplicationDebug.java │ │ └── AndroidManifest.xml │ ├── release │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── derek_s │ │ │ └── hubble_gallery │ │ │ └── base │ │ │ └── HubbleApplicationRelease.java │ └── androidTest │ │ └── java │ │ └── com │ │ └── derek_s │ │ └── hubble_gallery │ │ └── ApplicationTest.java ├── .gitignore ├── proguard-rules.pro └── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── .gitignore ├── README.md ├── gradlew.bat └── gradlew /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /app/src/main/res/values-land/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values-sw600dp-land/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 3 | 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/assets/fonts/Roboto-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/assets/fonts/Roboto-Black.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/assets/fonts/Roboto-Bold.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/assets/fonts/Roboto-Light.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/Roboto-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/assets/fonts/Roboto-Thin.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/Roboto-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/assets/fonts/Roboto-Italic.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/assets/fonts/Roboto-Medium.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/assets/fonts/Roboto-Regular.ttf -------------------------------------------------------------------------------- /app/src/main/res/drawable/sad_astronaut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable/sad_astronaut.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/assets/fonts/Roboto-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/assets/fonts/Roboto-BoldItalic.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/Roboto-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/assets/fonts/Roboto-ThinItalic.ttf -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/api/ApiClient.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.api; 2 | 3 | 4 | public class ApiClient { 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/assets/fonts/Roboto-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/assets/fonts/Roboto-BlackItalic.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/Roboto-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/assets/fonts/Roboto-LightItalic.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/Roboto-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/assets/fonts/Roboto-MediumItalic.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/RobotoCondensed-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/assets/fonts/RobotoCondensed-Bold.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/RobotoCondensed-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/assets/fonts/RobotoCondensed-Italic.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/RobotoCondensed-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/assets/fonts/RobotoCondensed-Light.ttf -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/drawer_shadow.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png -------------------------------------------------------------------------------- /app/src/main/assets/fonts/RobotoCondensed-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/assets/fonts/RobotoCondensed-Regular.ttf -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_info_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-hdpi/ic_info_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_star_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-hdpi/ic_star_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_info_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xhdpi/ic_info_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_star_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xhdpi/ic_star_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/assets/fonts/RobotoCondensed-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/assets/fonts/RobotoCondensed-BoldItalic.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/RobotoCondensed-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/assets/fonts/RobotoCondensed-LightItalic.ttf -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_favorite_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-hdpi/ic_favorite_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_settings_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-hdpi/ic_settings_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_info_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxhdpi/ic_info_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_star_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxhdpi/ic_star_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_info_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxxhdpi/ic_info_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_star_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxxhdpi/ic_star_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_arrow_back_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-hdpi/ic_arrow_back_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_fullscreen_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-hdpi/ic_fullscreen_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_more_vert_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-hdpi/ic_more_vert_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_favorite_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xhdpi/ic_favorite_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_more_vert_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xhdpi/ic_more_vert_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_settings_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xhdpi/ic_settings_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_favorite_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxhdpi/ic_favorite_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_settings_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxhdpi/ic_settings_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_arrow_drop_up_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-hdpi/ic_arrow_drop_up_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_filter_list_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-hdpi/ic_filter_list_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_arrow_back_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xhdpi/ic_arrow_back_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_filter_list_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xhdpi/ic_filter_list_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_fullscreen_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xhdpi/ic_fullscreen_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_arrow_back_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxhdpi/ic_arrow_back_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_filter_list_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxhdpi/ic_filter_list_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_fullscreen_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxhdpi/ic_fullscreen_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_more_vert_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxhdpi/ic_more_vert_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_arrow_back_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxxhdpi/ic_arrow_back_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_favorite_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxxhdpi/ic_favorite_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_fullscreen_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxxhdpi/ic_fullscreen_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_more_vert_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxxhdpi/ic_more_vert_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_settings_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxxhdpi/ic_settings_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_arrow_drop_down_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-hdpi/ic_arrow_drop_down_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_arrow_drop_up_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xhdpi/ic_arrow_drop_up_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_arrow_drop_up_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxhdpi/ic_arrow_drop_up_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_filter_list_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxxhdpi/ic_filter_list_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_favorite_outline_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-hdpi/ic_favorite_outline_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_keyboard_arrow_up_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-hdpi/ic_keyboard_arrow_up_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_arrow_drop_down_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xhdpi/ic_arrow_drop_down_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_favorite_outline_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xhdpi/ic_favorite_outline_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_keyboard_arrow_up_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xhdpi/ic_keyboard_arrow_up_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_arrow_drop_down_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxhdpi/ic_arrow_drop_down_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_favorite_outline_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxhdpi/ic_favorite_outline_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_arrow_drop_down_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxxhdpi/ic_arrow_drop_down_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_arrow_drop_up_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxxhdpi/ic_arrow_drop_up_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_keyboard_arrow_down_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-hdpi/ic_keyboard_arrow_down_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_keyboard_arrow_down_white_36dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-hdpi/ic_keyboard_arrow_down_white_36dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_keyboard_arrow_down_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xhdpi/ic_keyboard_arrow_down_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_keyboard_arrow_down_white_36dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xhdpi/ic_keyboard_arrow_down_white_36dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_keyboard_arrow_up_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxhdpi/ic_keyboard_arrow_up_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_favorite_outline_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxxhdpi/ic_favorite_outline_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_keyboard_arrow_up_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxxhdpi/ic_keyboard_arrow_up_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_keyboard_arrow_down_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxhdpi/ic_keyboard_arrow_down_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_keyboard_arrow_down_white_36dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxhdpi/ic_keyboard_arrow_down_white_36dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_keyboard_arrow_down_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxxhdpi/ic_keyboard_arrow_down_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_keyboard_arrow_down_white_36dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derekcsm/hubble_gallery/HEAD/app/src/main/res/drawable-xxxhdpi/ic_keyboard_arrow_down_white_36dp.png -------------------------------------------------------------------------------- /app/src/main/kotlin/com/derek_s/hubble_gallery/nav_drawer/dialog/DialogAboutListener.kt: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.nav_drawer.dialog 2 | 3 | interface DialogAboutListener { 4 | fun onShowIntroClicked() 5 | } -------------------------------------------------------------------------------- /app/src/main/res/anim/decelerate_interpolator.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/derek_s/hubble_gallery/nav_drawer/model/SectionObject.kt: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.nav_drawer.model; 2 | 3 | class SectionObject : SectionChildObject() { 4 | var isExpandable: Boolean = false 5 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Nov 09 19:12:23 PST 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 | -------------------------------------------------------------------------------- /app/src/debug/java/com/derek_s/hubble_gallery/base/HubbleApplicationDebug.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.base; 2 | 3 | public class HubbleApplicationDebug extends HubbleApplication { 4 | 5 | @Override 6 | public void onCreate() { 7 | super.onCreate(); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/internal/di/ActivityScope.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.internal.di; 2 | 3 | import javax.inject.Scope; 4 | 5 | /** 6 | * Objects that should only live on the activity should use this 7 | */ 8 | 9 | @Scope 10 | public @interface ActivityScope { 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/selector_default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 9 | -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /app/src/main/kotlin/com/derek_s/hubble_gallery/_shared/model/Tiles.kt: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery._shared.model 2 | 3 | import com.google.gson.Gson 4 | import java.util.* 5 | 6 | class Tiles { 7 | 8 | var tiles: ArrayList = ArrayList() 9 | 10 | fun serialize(): String { 11 | val gson = Gson() 12 | return gson.toJson(this) 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /app/src/main/res/anim/fade_in_shadow.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/anim/fade_out_shadow.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_in_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_out_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/release/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/derek_s/hubble_gallery/nav_drawer/model/SectionChildObject.kt: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.nav_drawer.model; 2 | 3 | open class SectionChildObject { 4 | 5 | constructor() { 6 | } 7 | 8 | constructor(title: String, query: String) { 9 | this.sectionTitle = title 10 | this.query = query 11 | } 12 | 13 | var sectionTitle: String = "" 14 | var query: String = "" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/selector_circle_default.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/release/java/com/derek_s/hubble_gallery/base/HubbleApplicationRelease.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.base; 2 | 3 | import com.crashlytics.android.Crashlytics; 4 | 5 | import io.fabric.sdk.android.Fabric; 6 | 7 | public class HubbleApplicationRelease extends HubbleApplication { 8 | 9 | @Override 10 | public void onCreate() { 11 | super.onCreate(); 12 | Fabric.with(this, new Crashlytics()); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_grid_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/derek_s/hubble_gallery/nav_drawer/views/NavigationView.kt: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.nav_drawer.views 2 | 3 | import android.support.v7.widget.RecyclerView 4 | import com.derek_s.hubble_gallery.nav_drawer.model.SectionChildObject 5 | 6 | interface NavigationView { 7 | val recycler: RecyclerView 8 | get 9 | 10 | fun selectSection(section: SectionChildObject) { 11 | } 12 | 13 | fun deselectFavorites() { 14 | } 15 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/com/derek_s/hubble_gallery/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | # built application files 4 | *.apk 5 | *.ap_ 6 | *.jks 7 | 8 | # files for the dex VM 9 | *.dex 10 | 11 | # Java class files 12 | *.class 13 | 14 | # generated files 15 | bin/ 16 | gen/ 17 | 18 | # Local configuration file (sdk path, etc) 19 | local.properties 20 | 21 | # Android Studio 22 | .idea/ 23 | .gradle 24 | gradle 25 | /*/local.properties 26 | /*/out 27 | /*/*/build 28 | build 29 | /*/*/production 30 | *.iml 31 | *.iws 32 | *.ipr 33 | *~ 34 | *.swp 35 | 36 | app/fabric.properties -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | # built application files 4 | *.apk 5 | *.ap_ 6 | *.jks 7 | 8 | # files for the dex VM 9 | *.dex 10 | 11 | # Java class files 12 | *.class 13 | 14 | # generated files 15 | bin/ 16 | gen/ 17 | 18 | # Local configuration file (sdk path, etc) 19 | local.properties 20 | 21 | # Android Studio 22 | .idea/ 23 | .gradle 24 | gradle 25 | /*/local.properties 26 | /*/out 27 | /*/*/build 28 | build 29 | /*/*/production 30 | *.iml 31 | *.iws 32 | *.ipr 33 | *~ 34 | *.swp 35 | 36 | fabric.properties -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_circle_default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/values-sw600dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24dp 4 | 12dp 5 | 80dp 6 | 7 | 8 | 400dp 9 | 52dp 10 | 11 | 12 | 3 13 | 14 | 15 | 32dp 16 | 48dp 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/derek_s/hubble_gallery/_shared/model/TileObject.kt: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery._shared.model 2 | 3 | import com.google.gson.Gson 4 | 5 | class TileObject { 6 | 7 | var id: String = "" 8 | var title: String = "" 9 | var href: String = "" 10 | var src: String = "" 11 | 12 | fun serialize(): String { 13 | val gson = Gson() 14 | return gson.toJson(this) 15 | } 16 | 17 | companion object { 18 | fun create(serializedData: String): TileObject { 19 | val gson = Gson() 20 | return gson.fromJson(serializedData, TileObject::class.java) 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/res/anim/fade_in_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/anim/fade_out_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res-details/layout/act_image_viewer.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/base/Constants.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.base; 2 | 3 | import android.os.Environment; 4 | 5 | public class Constants { 6 | 7 | public static final String MODE_KEY = "current_mode"; 8 | public static final String PARAM_TILE_KEY = "tile_param"; 9 | public static final String PARAM_DETAILS_KEY = "details_param"; 10 | public static final String ONBOARDING_SHOWN = "onboarding_shown"; 11 | public static final int LOADED_MODE = 0; 12 | public static final int FAVORITES_MODE = 1; 13 | public static final int SEARCH_MODE = 2; 14 | 15 | public static String imageDirectory() { 16 | return Environment.getExternalStorageDirectory() + "/Pictures/Hubble"; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /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 /Users/dereksmith/Documents/ADT/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/res/anim/zoom_in_exit.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /app/src/main/res-welcome/layout/act_welcome.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 12 | 13 | 14 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/derek_s/hubble_gallery/detailspage/DetailsContract.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.detailspage; 2 | 3 | import android.content.Intent; 4 | import android.widget.ImageView; 5 | 6 | import com.derek_s.hubble_gallery._shared.model.DetailsObject; 7 | import com.github.ksoichiro.android.observablescrollview.ObservableScrollView; 8 | 9 | public interface DetailsContract { 10 | 11 | void showLoadingAnimation(boolean show, int type); 12 | 13 | void populateDetails(DetailsObject detailsObject); 14 | 15 | void showZeroState(boolean show); 16 | 17 | void generatePalette(); 18 | 19 | void openActivityIntent(Intent intent); 20 | 21 | void openImageViewer(); 22 | 23 | ImageView getIvDisplay(); 24 | 25 | ObservableScrollView getScrollView(); 26 | 27 | void updateMenu(); 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/derek_s/hubble_gallery/_shared/model/DetailsObject.kt: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery._shared.model; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.annotations.Expose; 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | class DetailsObject { 8 | 9 | @Expose 10 | var description: String = "" 11 | 12 | @Expose 13 | var names: String = "" 14 | 15 | @SerializedName("image_type") 16 | @Expose 17 | var imageType: String = "" 18 | 19 | @Expose 20 | var credit: String = "" 21 | 22 | fun serialize(): String { 23 | val gson = Gson() 24 | return gson.toJson(this) 25 | } 26 | 27 | companion object { 28 | fun create(serializedData: String): DetailsObject { 29 | val gson = Gson() 30 | return gson.fromJson(serializedData, DetailsObject::class.java) 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /app/src/main/res-navigation/layout/frag_nav_drawer.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 15 | 16 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/ui/widgets/SquareImageView.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.ui.widgets; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.ImageView; 6 | 7 | /** 8 | * Created by dereksmith on 15-03-01. 9 | */ 10 | public class SquareImageView extends ImageView { 11 | 12 | public SquareImageView(Context context) { 13 | super(context); 14 | } 15 | 16 | public SquareImageView(Context context, AttributeSet attrs) { 17 | super(context, attrs); 18 | } 19 | 20 | public SquareImageView(Context context, AttributeSet attrs, int defStyle) { 21 | super(context, attrs, defStyle); 22 | } 23 | 24 | @Override 25 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 26 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 27 | 28 | int width = getMeasuredWidth(); 29 | setMeasuredDimension(width, width); 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/internal/di/ActivityComponent.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.internal.di; 2 | 3 | import com.derek_s.hubble_gallery.base.ActBase; 4 | import com.derek_s.hubble_gallery.base.FragBase; 5 | import com.derek_s.hubble_gallery.detailspage.DetailsActivity; 6 | import com.derek_s.hubble_gallery.home.ActHome; 7 | import com.derek_s.hubble_gallery.imageviewer.ImageViewerActivity; 8 | import com.derek_s.hubble_gallery.ui.activities.ActWelcome; 9 | 10 | import dagger.Component; 11 | 12 | /** 13 | * This component injects Activities and Fragments 14 | */ 15 | 16 | @ActivityScope 17 | @Component(dependencies = {AppComponent.class}) 18 | public interface ActivityComponent { 19 | 20 | void inject(ActBase app); 21 | 22 | void inject(DetailsActivity app); 23 | 24 | void inject(ActHome app); 25 | 26 | void inject(ImageViewerActivity app); 27 | 28 | void inject(ActWelcome app); 29 | 30 | void inject(FragBase app); 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/res/menu/act_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 12 | 13 | 14 | 15 | 20 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res-navigation/layout/item_section.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 12 | 13 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/base/ActBase.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.base; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v7.app.AppCompatActivity; 6 | 7 | import com.derek_s.hubble_gallery.internal.di.ActivityComponent; 8 | import com.derek_s.hubble_gallery.internal.di.DaggerActivityComponent; 9 | 10 | public abstract class ActBase extends AppCompatActivity { 11 | 12 | @Override 13 | protected void onCreate(@Nullable Bundle savedState) { 14 | super.onCreate(savedState); 15 | 16 | injectComponent(DaggerActivityComponent.builder() 17 | .appComponent(((HubbleApplication) getApplication()).getAppComponent()) 18 | .build()); 19 | } 20 | 21 | /** 22 | *

23 | * This method must be implemented 24 | *

25 | * component.inject(this) 26 | * 27 | * @param component 28 | */ 29 | protected abstract void injectComponent(ActivityComponent component); 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/utils/ui/IndeterminateAnimator.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.utils.ui; 2 | 3 | import android.os.Handler; 4 | import android.view.View; 5 | 6 | import com.daimajia.androidanimations.library.Techniques; 7 | import com.daimajia.androidanimations.library.YoYo; 8 | import com.derek_s.hubble_gallery.ui.widgets.CircleProgressView; 9 | 10 | /** 11 | * Created by dereksmith on 15-03-22. 12 | */ 13 | public class IndeterminateAnimator { 14 | 15 | public static void show(final CircleProgressView prog, Techniques technique) { 16 | prog.setVisibility(View.VISIBLE); 17 | YoYo.with(technique).duration(300).playOn(prog); 18 | } 19 | 20 | public static void stop(final CircleProgressView prog, Techniques technique) { 21 | YoYo.with(technique).duration(300).playOn(prog); 22 | new Handler().postDelayed(new Runnable() { 23 | @Override 24 | public void run() { 25 | prog.setVisibility(View.GONE); 26 | } 27 | }, 320); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/base/FragBase.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.base; 2 | 3 | import android.content.res.Resources; 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | 7 | import com.derek_s.hubble_gallery.internal.di.DaggerActivityComponent; 8 | import com.derek_s.hubble_gallery.utils.FavoriteUtils; 9 | import com.derek_s.hubble_gallery.utils.network.NetworkUtil; 10 | 11 | import javax.inject.Inject; 12 | 13 | public class FragBase extends Fragment { 14 | 15 | @Inject 16 | public Resources resources; 17 | @Inject 18 | public NetworkUtil networkUtil; 19 | @Inject 20 | public TinyDB db; 21 | @Inject 22 | public FavoriteUtils favoriteUtils; 23 | 24 | @Override 25 | public void onCreate(Bundle savedState) { 26 | super.onCreate(savedState); 27 | DaggerActivityComponent.builder() 28 | .appComponent(((HubbleApplication) getActivity().getApplication()).getAppComponent()) 29 | .build() 30 | .inject(this); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/base/HubbleApplication.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.base; 2 | 3 | import android.app.Application; 4 | 5 | import com.crashlytics.android.Crashlytics; 6 | import com.derek_s.hubble_gallery.internal.di.AppComponent; 7 | import com.derek_s.hubble_gallery.internal.di.AppModule; 8 | import com.derek_s.hubble_gallery.internal.di.DaggerAppComponent; 9 | 10 | import io.fabric.sdk.android.Fabric; 11 | 12 | public class HubbleApplication extends Application { 13 | 14 | private AppComponent appComponent; 15 | 16 | @Override 17 | public void onCreate() { 18 | super.onCreate(); 19 | Fabric.with(this, new Crashlytics()); 20 | this.initializeInjector(); 21 | } 22 | 23 | private void initializeInjector() { 24 | this.appComponent = DaggerAppComponent 25 | .builder() 26 | .appModule(new AppModule(this)) 27 | .build(); 28 | 29 | this.appComponent.inject(this); 30 | } 31 | 32 | public AppComponent getAppComponent() { 33 | return appComponent; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/ui/adapters/OnboardingFragmentPager.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.ui.adapters; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentManager; 5 | import android.support.v4.app.FragmentPagerAdapter; 6 | import android.util.Log; 7 | 8 | import com.derek_s.hubble_gallery.ui.fragments.FragWelcomeInfo; 9 | import com.derek_s.hubble_gallery.ui.fragments.FragWelcomeOutline; 10 | 11 | /** 12 | * Created by dereksmith on 15-05-04. 13 | */ 14 | public class OnboardingFragmentPager extends FragmentPagerAdapter { 15 | private String TAG = getClass().getSimpleName(); 16 | 17 | public OnboardingFragmentPager(FragmentManager fm) { 18 | super(fm); 19 | } 20 | 21 | @Override 22 | public Fragment getItem(int position) { 23 | Log.i(TAG, "getItem pos: " + position); 24 | if (position == 0) { 25 | return new FragWelcomeOutline(); 26 | } else { 27 | return FragWelcomeInfo.newInstance(position); 28 | } 29 | } 30 | 31 | @Override 32 | public int getCount() { 33 | return 5; 34 | } 35 | 36 | } 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_tile.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/internal/di/AppComponent.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.internal.di; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | import android.net.ConnectivityManager; 6 | 7 | import com.derek_s.hubble_gallery.base.HubbleApplication; 8 | import com.derek_s.hubble_gallery.base.TinyDB; 9 | import com.derek_s.hubble_gallery.detailspage.DetailsPresenter; 10 | import com.derek_s.hubble_gallery.utils.FavoriteUtils; 11 | import com.derek_s.hubble_gallery.utils.network.NetworkUtil; 12 | import com.google.gson.Gson; 13 | 14 | import javax.inject.Singleton; 15 | 16 | import dagger.Component; 17 | 18 | @Singleton 19 | @Component(modules = {AppModule.class}) 20 | public interface AppComponent { 21 | 22 | Context context(); 23 | 24 | Resources resources(); 25 | 26 | ConnectivityManager provideConnectivityManager(); 27 | 28 | NetworkUtil provideNetworkUtil(); 29 | 30 | TinyDB provideTinyDB(); 31 | 32 | DetailsPresenter provideActDetailsPresenter(); 33 | 34 | FavoriteUtils provideFavoriteUtils(); 35 | 36 | Gson provideGson(); 37 | 38 | void inject(HubbleApplication app); 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ff131313 4 | #ff000000 5 | #00BCD4 6 | 7 | #ff151515 8 | #006064 9 | 10 | 11 | #89000000 12 | #de000000 13 | #de000000 14 | #89000000 15 | #1f000000 16 | 17 | #89ffffff 18 | #deffffff 19 | #deffffff 20 | #89ffffff 21 | #1fffffff 22 | 23 | #00BCD4 24 | #6700bcd4 25 | #2100bcd4 26 | 27 | #66000000 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/utils/ui/Toasty.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.utils.ui; 2 | 3 | import android.content.Context; 4 | 5 | import com.github.johnpersano.supertoasts.SuperToast; 6 | 7 | /** 8 | * Created by dereksmith on 15-04-11. 9 | */ 10 | public class Toasty { 11 | 12 | public static int LENGTH_LONG = 3000; 13 | public static int LENGTH_MEDIUM = 2000; 14 | public static int LENGTH_SHORT = 1000; 15 | 16 | public static void show(Context c, String text, int duration) { 17 | SuperToast superToast = new SuperToast(c); 18 | superToast.setDuration(duration); 19 | superToast.setText(text); 20 | superToast.setAnimations(SuperToast.Animations.POPUP); 21 | superToast.setBackground(SuperToast.Background.GRAY); 22 | superToast.show(); 23 | } 24 | 25 | public static void show(Context c, int textRes, int duration) { 26 | SuperToast superToast = new SuperToast(c); 27 | superToast.setDuration(duration); 28 | superToast.setText(c.getResources().getString(textRes)); 29 | superToast.setAnimations(SuperToast.Animations.POPUP); 30 | superToast.setBackground(SuperToast.Background.GRAY); 31 | superToast.show(); 32 | } 33 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/com/derek_s/hubble_gallery/nav_drawer/adapters/NavigationAdapterItem.kt: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.nav_drawer.adapters 2 | 3 | import android.support.annotation.IntDef 4 | import com.bignerdranch.expandablerecyclerview.Model.ParentListItem 5 | 6 | class NavigationAdapterItem(`object`: Any?, viewType: Long, childObjectList: List?) : 7 | ParentListItem { 8 | 9 | @ViewType 10 | var viewType: Long = 0 11 | var `object`: Any? 12 | var childObjectList: List? 13 | var isSelected: Boolean = false 14 | 15 | init { 16 | this.`object` = `object` 17 | this.viewType = viewType 18 | this.childObjectList = childObjectList 19 | } 20 | 21 | override fun getChildItemList(): List? { 22 | return childObjectList 23 | } 24 | 25 | override fun isInitiallyExpanded(): Boolean { 26 | return isSelected 27 | } 28 | 29 | @Retention(AnnotationRetention.SOURCE) 30 | @IntDef(HEADER, STANDALONE_SECTION, SECTION, GROUP) 31 | annotation class ViewType 32 | 33 | companion object { 34 | const val HEADER: Long = 0 35 | const val STANDALONE_SECTION: Long = 1 36 | const val SECTION: Long = 2 37 | const val GROUP: Long = 3 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/res-details/layout/zero_state_details.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 19 | 20 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 8dp 5 | 72dp 6 | 24dp 7 | ?attr/actionBarSize 8 | 9 | 10 | 112sp 11 | 56sp 12 | 45sp 13 | 34sp 14 | 24sp 15 | 20sp 16 | 14sp 17 | 14sp 18 | 12sp 19 | 20 | 21 | 320 22 | 350 23 | 0.6 24 | 25 | 26 | 300dp 27 | 48dp 28 | 29 | 30 | 2 31 | 32 | 33 | 24dp 34 | 32dp 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/res/layout/frag_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 16 | 17 | 26 | 27 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/utils/ui/ToolbarTitle.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.utils.ui; 2 | 3 | import android.content.Context; 4 | import android.view.Gravity; 5 | import android.view.View; 6 | import android.view.animation.Animation; 7 | import android.view.animation.AnimationUtils; 8 | import android.widget.TextSwitcher; 9 | import android.widget.TextView; 10 | import android.widget.ViewSwitcher.ViewFactory; 11 | 12 | import com.derek_s.hubble_gallery.R; 13 | 14 | public class ToolbarTitle { 15 | private Context c; 16 | private ViewFactory mFactory = new ViewFactory() { 17 | 18 | @Override 19 | public View makeView() { 20 | TextView t = new TextView(c); 21 | t.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT); 22 | t.setTextAppearance(c, R.style.text_title_dark); 23 | t.setTypeface(FontFactory.getCondensedRegular(c)); 24 | t.setAllCaps(true); 25 | return t; 26 | } 27 | }; 28 | 29 | public TextSwitcher init(TextSwitcher switcher, Context context) { 30 | c = context; 31 | switcher.setFactory(mFactory); 32 | 33 | Animation in = AnimationUtils.loadAnimation(c, 34 | R.anim.fade_in_right); 35 | Animation out = AnimationUtils.loadAnimation(c, 36 | R.anim.fade_out_right); 37 | 38 | switcher.setInAnimation(in); 39 | switcher.setOutAnimation(out); 40 | 41 | return switcher; 42 | } 43 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hubble Gallery (DEPRECATED) 2 | Discover and read about the Hubble Telescope's best images. 3 | 4 | ![icon](http://i.imgur.com/wEWW2OH.png) 5 | 6 | ---- 7 | ### [Google Play listing →](https://play.google.com/store/apps/details?id=com.derek_s.hubble_gallery) 8 | 9 | 10 | Maintained by [derekcsm](http://derekcsm.xyz/) 11 | 12 | Contributions by: 13 | 14 | - [PedroVictorB](https://github.com/PedroVictorB) 15 | 16 | General code style 17 | ------- 18 | 19 | - use 2 space `indents` and 4 space `continuation indents` for Java and Kotlin, and 2 space for indents & continuation in XML, we're slowing moving to that 20 | - try your best not to exceed horizontal line length 21 | - don't include "created by" or any other tags at top of classes, if you find any please remove them 22 | 23 | License 24 | ------- 25 | 26 | Licensed under the Apache License, Version 2.0 (the "License"); 27 | you may not use this file except in compliance with the License. 28 | You may obtain a copy of the License at 29 | 30 | http://www.apache.org/licenses/LICENSE-2.0 31 | 32 | Unless required by applicable law or agreed to in writing, software 33 | distributed under the License is distributed on an "AS IS" BASIS, 34 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 35 | See the License for the specific language governing permissions and 36 | limitations under the License. 37 | -------------------------------------------------------------------------------- /app/src/main/res/layout/act_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 15 | 21 | 22 | 27 | 28 | 29 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/res/layout/zero_state_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 22 | 23 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res-welcome/layout/frag_welcome_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 22 | 23 | 37 | -------------------------------------------------------------------------------- /app/src/main/res-navigation/layout/item_group.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 23 | 24 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/derek_s/hubble_gallery/imageviewer/ImageViewerActivity.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.imageviewer; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | 6 | import com.derek_s.hubble_gallery.R; 7 | import com.derek_s.hubble_gallery.base.ActBase; 8 | import com.derek_s.hubble_gallery.internal.di.ActivityComponent; 9 | import com.derek_s.hubble_gallery.ui.widgets.TouchImageView; 10 | import com.squareup.picasso.Picasso; 11 | 12 | import butterknife.Bind; 13 | import butterknife.ButterKnife; 14 | 15 | public class ImageViewerActivity extends ActBase { 16 | 17 | public static final String EXTRA_IMAGE_SRC = "extra_successful_src"; 18 | @Bind(R.id.iv_fullscreen) 19 | TouchImageView ivFullscreen; 20 | private String imgSrc; 21 | 22 | @Override 23 | protected void onCreate(Bundle savedState) { 24 | super.onCreate(savedState); 25 | setContentView(R.layout.act_image_viewer); 26 | ButterKnife.bind(this); 27 | 28 | Intent intent = getIntent(); 29 | if (intent != null) { 30 | imgSrc = intent.getStringExtra(EXTRA_IMAGE_SRC); 31 | } 32 | 33 | if (savedState != null) 34 | imgSrc = savedState.getString(EXTRA_IMAGE_SRC); 35 | 36 | Picasso.with(this).load(imgSrc).into(ivFullscreen); 37 | } 38 | 39 | @Override 40 | public void onSaveInstanceState(Bundle outState) { 41 | outState.putString(EXTRA_IMAGE_SRC, imgSrc); 42 | super.onSaveInstanceState(outState); 43 | } 44 | 45 | @Override 46 | protected void injectComponent(ActivityComponent component) { 47 | component.inject(this); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/ui/adapters/RecyclerViewItemClickListener.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.ui.adapters; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.GestureDetector; 6 | import android.view.MotionEvent; 7 | import android.view.View; 8 | 9 | /** 10 | * Credit to sam_chordas for the code and idea 11 | */ 12 | public class RecyclerViewItemClickListener implements RecyclerView.OnItemTouchListener { 13 | 14 | private GestureDetector gestureDetector; 15 | private OnItemClickListener listener; 16 | 17 | public RecyclerViewItemClickListener(Context context, OnItemClickListener listener) { 18 | this.listener = listener; 19 | gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { 20 | @Override 21 | public boolean onSingleTapUp(MotionEvent e) { 22 | return true; 23 | } 24 | }); 25 | } 26 | 27 | @Override 28 | public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { 29 | 30 | } 31 | 32 | @Override 33 | public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) { 34 | View childView = view.findChildViewUnder(e.getX(), e.getY()); 35 | if (childView != null && listener != null && gestureDetector.onTouchEvent(e)) { 36 | listener.onItemClick(childView, view.getChildPosition(childView)); 37 | return true; 38 | } 39 | return false; 40 | } 41 | 42 | @Override 43 | public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { 44 | } 45 | 46 | public interface OnItemClickListener { 47 | void onItemClick(View v, int position); 48 | } 49 | } -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/internal/di/AppModule.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.internal.di; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import android.content.res.Resources; 6 | import android.net.ConnectivityManager; 7 | 8 | import com.derek_s.hubble_gallery.base.TinyDB; 9 | import com.derek_s.hubble_gallery.utils.network.NetworkUtil; 10 | import com.google.gson.Gson; 11 | 12 | import javax.inject.Singleton; 13 | 14 | import dagger.Module; 15 | import dagger.Provides; 16 | 17 | /** 18 | * This module resolves everything on an AppContext, things that need to be instantiated 19 | * only once or need an App Context. 20 | */ 21 | 22 | @Module 23 | public class AppModule { 24 | 25 | private final Application application; 26 | 27 | public AppModule(Application application) { 28 | this.application = application; 29 | } 30 | 31 | @Provides 32 | Context provideContext() { 33 | return application.getBaseContext(); 34 | } 35 | 36 | @Provides 37 | @Singleton 38 | Resources provideResources(Context context) { 39 | return context.getResources(); 40 | } 41 | 42 | @Provides 43 | @Singleton 44 | ConnectivityManager provideConnectivityManager() { 45 | return (ConnectivityManager) application.getSystemService(Context.CONNECTIVITY_SERVICE); 46 | } 47 | 48 | @Provides 49 | @Singleton 50 | NetworkUtil provideNetworkStateManager(ConnectivityManager connectivityManagerCompat, Context context) { 51 | return new NetworkUtil(connectivityManagerCompat, context); 52 | } 53 | 54 | @Provides 55 | @Singleton 56 | TinyDB provideTinyDb(Context context) { 57 | return new TinyDB(context); 58 | } 59 | 60 | @Provides 61 | @Singleton 62 | Gson provideGson() { 63 | return new Gson(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/res-details/menu/menu_act_details.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 12 | 13 | 19 | 20 | 25 | 26 | 31 | 32 | 37 | 38 | 43 | 44 | 49 | 50 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/utils/FavoriteUtils.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.utils; 2 | 3 | import com.derek_s.hubble_gallery._shared.model.TileObject; 4 | import com.derek_s.hubble_gallery._shared.model.Tiles; 5 | import com.derek_s.hubble_gallery.base.TinyDB; 6 | import com.google.gson.Gson; 7 | 8 | import javax.inject.Inject; 9 | import javax.inject.Singleton; 10 | 11 | @Singleton 12 | public class FavoriteUtils { 13 | 14 | private static final String FAVORITES_KEY = "favorites_key"; 15 | 16 | @Inject 17 | TinyDB tinyDB; 18 | @Inject 19 | Gson gson; 20 | 21 | @Inject 22 | public FavoriteUtils() { 23 | } 24 | 25 | public void saveFavorite(TileObject tileObject) { 26 | Tiles currentFaves = getFavorites(); 27 | if (currentFaves == null) 28 | currentFaves = new Tiles(); 29 | 30 | currentFaves.getTiles().add(tileObject); 31 | tinyDB.putString(FAVORITES_KEY, currentFaves.serialize()); 32 | } 33 | 34 | public Tiles getFavorites() { 35 | return gson.fromJson(tinyDB.getString(FAVORITES_KEY), Tiles.class); 36 | } 37 | 38 | public void removeFavorite(TileObject tileObject) { 39 | Tiles currentFaves = getFavorites(); 40 | 41 | for (int i = 0; i < currentFaves.getTiles().size(); i++) { 42 | TileObject curTile = currentFaves.getTiles().get(i); 43 | 44 | if (curTile.getId().equals(tileObject.getId())) 45 | currentFaves.getTiles().remove(i); 46 | } 47 | 48 | tinyDB.putString(FAVORITES_KEY, currentFaves.serialize()); 49 | } 50 | 51 | public boolean isFavorited(TileObject tileObject) { 52 | Tiles currentFaves = getFavorites(); 53 | 54 | if (currentFaves == null) 55 | return false; 56 | 57 | for (TileObject curTile : currentFaves.getTiles()) { 58 | if (curTile.getId().equals(tileObject.getId())) 59 | return true; 60 | } 61 | return false; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/res/layout-land/zero_state_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 18 | 19 | 26 | 27 | 35 | 36 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/utils/network/NetworkUtil.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.utils.network; 2 | 3 | import android.content.Context; 4 | import android.net.ConnectivityManager; 5 | import android.net.NetworkInfo; 6 | 7 | import com.derek_s.hubble_gallery.R; 8 | import com.derek_s.hubble_gallery.utils.ui.Toasty; 9 | 10 | import javax.inject.Inject; 11 | 12 | public class NetworkUtil { 13 | public static int TYPE_WIFI = 1; 14 | public static int TYPE_MOBILE = 2; 15 | public static int TYPE_NOT_CONNECTED = 0; 16 | 17 | private final ConnectivityManager connectivityManager; 18 | private Context context; 19 | 20 | @Inject 21 | public NetworkUtil(ConnectivityManager connectivityManager, Context context) { 22 | this.connectivityManager = connectivityManager; 23 | this.context = context; 24 | } 25 | 26 | public int getConnectivityStatus() { 27 | NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo(); 28 | if (null != activeNetwork) { 29 | if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI) 30 | return TYPE_WIFI; 31 | 32 | if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) 33 | return TYPE_MOBILE; 34 | } 35 | return TYPE_NOT_CONNECTED; 36 | } 37 | 38 | public String getConnectivityStatusString() { 39 | int conn = getConnectivityStatus(); 40 | String status = null; 41 | if (conn == NetworkUtil.TYPE_WIFI) { 42 | status = "Wifi enabled"; 43 | } else if (conn == NetworkUtil.TYPE_MOBILE) { 44 | status = "Mobile data enabled"; 45 | } else if (conn == NetworkUtil.TYPE_NOT_CONNECTED) { 46 | status = "Not connected to Internet"; 47 | } 48 | return status; 49 | } 50 | 51 | public void toastNoConnection() { 52 | Toasty.show(context, R.string.no_connection, Toasty.LENGTH_MEDIUM); 53 | } 54 | 55 | public boolean isConnected() { 56 | int conn = getConnectivityStatus(); 57 | return conn != NetworkUtil.TYPE_NOT_CONNECTED; 58 | } 59 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/com/derek_s/hubble_gallery/nav_drawer/adapters/SectionViewHolder.kt: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.nav_drawer.adapters 2 | 3 | import android.content.Context 4 | import android.support.v4.content.ContextCompat 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import android.widget.TextView 9 | import butterknife.bindView 10 | import com.bignerdranch.expandablerecyclerview.ViewHolder.ChildViewHolder 11 | import com.derek_s.hubble_gallery.R 12 | import com.derek_s.hubble_gallery.nav_drawer.model.SectionChildObject 13 | import com.derek_s.hubble_gallery.utils.ui.FontFactory 14 | 15 | class SectionViewHolder private constructor(itemView: View) : ChildViewHolder(itemView) { 16 | 17 | val tvTitle: TextView by bindView(R.id.tv_title) 18 | 19 | init { 20 | beautifyViews() 21 | } 22 | 23 | fun beautifyViews() { 24 | tvTitle.typeface = FontFactory.getRegular(itemView.context) 25 | } 26 | 27 | fun onBind(section: SectionChildObject, listener: NavDrawerAdapter.NavAdapterListener, 28 | pos: Int, selectedQuery: String) { 29 | tvTitle.text = section.sectionTitle 30 | 31 | if (section.query.equals(selectedQuery)) { 32 | tvTitle.setBackgroundColor(ContextCompat.getColor(itemView.context, R.color.focused_color)); 33 | tvTitle.setTextColor(ContextCompat.getColor(itemView.context, R.color.seleted_item_color)); 34 | } else { 35 | tvTitle.setBackgroundResource(R.drawable.selector_default); 36 | tvTitle.setTextColor(ContextCompat.getColor(itemView.context, R.color.body_dark_theme)); 37 | } 38 | 39 | tvTitle.setOnClickListener { 40 | listener.onSectionClicked(section) 41 | listener.setSelectedQuery(section.query) 42 | } 43 | } 44 | 45 | companion object { 46 | fun create(context: Context, viewGroup: ViewGroup): SectionViewHolder { 47 | return SectionViewHolder(LayoutInflater.from(context).inflate(R.layout.item_section, 48 | viewGroup, false)) 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 31 | 32 | 33 | 36 | 42 | 45 | 46 | 47 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/main/res-navigation/layout/dialog_about.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 17 | 18 | 24 | 25 | 31 | 32 | 33 | 34 | 37 | 38 | 46 | 47 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /app/src/main/res-welcome/layout/frag_welcome_outline.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 25 | 26 | 42 | 43 | 55 | 56 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/derek_s/hubble_gallery/nav_drawer/adapters/NavDrawerAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.nav_drawer.adapters 2 | 3 | import android.content.Context 4 | import android.view.ViewGroup 5 | import com.bignerdranch.expandablerecyclerview.Adapter.ExpandableRecyclerAdapter 6 | import com.bignerdranch.expandablerecyclerview.Model.ParentListItem 7 | import com.derek_s.hubble_gallery.nav_drawer.model.SectionChildObject 8 | import java.util.* 9 | 10 | class NavDrawerAdapter(context: Context, parentItemList: ArrayList, 11 | listener: NavAdapterListener) : 12 | ExpandableRecyclerAdapter(parentItemList) { 13 | 14 | private val TAG = "NavDrawerAdapter" 15 | private val mContext: Context 16 | private val listener: NavAdapterListener 17 | 18 | private var selectedQuery = "entire"; 19 | 20 | init { 21 | mContext = context 22 | this.listener = listener 23 | } 24 | 25 | override fun onCreateParentViewHolder(parentViewGroup: ViewGroup): GroupViewHolder? { 26 | return GroupViewHolder.create(mContext, parentViewGroup) 27 | } 28 | 29 | override fun onCreateChildViewHolder(childViewGroup: ViewGroup): SectionViewHolder? { 30 | return SectionViewHolder.create(mContext, childViewGroup) 31 | } 32 | 33 | override fun onBindParentViewHolder(parentViewHolder: GroupViewHolder, position: Int, 34 | parentListItem: ParentListItem) { 35 | parentViewHolder.onBind(parentListItem as NavigationAdapterItem, listener, position, selectedQuery) 36 | } 37 | 38 | override fun onBindChildViewHolder(childViewHolder: SectionViewHolder, position: Int, 39 | childListItem: Any) { 40 | childViewHolder.onBind(childListItem as SectionChildObject, listener, position, selectedQuery) 41 | } 42 | 43 | fun setSelectedQuery(query: String) { 44 | selectedQuery = query 45 | notifyDataSetChanged() 46 | } 47 | 48 | fun getSelectedQuery(): String { 49 | return selectedQuery 50 | } 51 | 52 | interface NavAdapterListener { 53 | fun onSectionClicked(section: SectionChildObject) 54 | 55 | fun setSelectedQuery(selectedQuery: String) 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/ui/fragments/FragWelcomeOutline.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.ui.fragments; 2 | 3 | import android.os.Bundle; 4 | import android.os.Handler; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | 10 | import com.daimajia.androidanimations.library.Techniques; 11 | import com.daimajia.androidanimations.library.YoYo; 12 | import com.derek_s.hubble_gallery.R; 13 | import com.derek_s.hubble_gallery.base.FragBase; 14 | import com.derek_s.hubble_gallery.utils.svg.SvgView; 15 | import com.derek_s.hubble_gallery.utils.ui.FontFactory; 16 | 17 | import butterknife.Bind; 18 | import butterknife.ButterKnife; 19 | 20 | public class FragWelcomeOutline extends FragBase { 21 | 22 | @Bind(R.id.hubble_outline) 23 | SvgView hubbleOutline; 24 | @Bind(R.id.tv_app_title) 25 | TextView tvTitle; 26 | @Bind(R.id.tv_scroll_down) 27 | TextView tvScrollDown; 28 | Handler showTitleHandler; 29 | 30 | @Override 31 | public void onCreate(Bundle savedState) { 32 | super.onCreate(savedState); 33 | } 34 | 35 | @Override 36 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 37 | Bundle savedState) { 38 | View rootView = inflater.inflate(R.layout.frag_welcome_outline, container, false); 39 | ButterKnife.bind(this, rootView); 40 | 41 | /* 42 | show initial intro animation 43 | */ 44 | YoYo.with(Techniques.FadeIn).duration(800).playOn(hubbleOutline); 45 | hubbleOutline.setSvgResource(R.raw.hubble_outline); 46 | hubbleOutline.setVisibility(View.VISIBLE); 47 | tvTitle.setTypeface(FontFactory.getCondensedLight(getActivity())); 48 | tvScrollDown.setTypeface(FontFactory.getCondensedRegular(getActivity())); 49 | 50 | showTitleHandler = new Handler(); 51 | showTitleHandler.postDelayed(new Runnable() { 52 | @Override 53 | public void run() { 54 | tvTitle.setVisibility(View.VISIBLE); 55 | YoYo.with(Techniques.FadeInUp).duration(1000).playOn(tvTitle); 56 | tvScrollDown.setVisibility(View.VISIBLE); 57 | YoYo.with(Techniques.FadeIn).duration(1000).playOn(tvScrollDown); 58 | } 59 | }, 4000); 60 | 61 | return rootView; 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/api/GetDetails.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.api; 2 | 3 | import android.os.AsyncTask; 4 | import android.util.Log; 5 | 6 | import com.derek_s.hubble_gallery._shared.model.DetailsObject; 7 | 8 | import org.jsoup.Jsoup; 9 | import org.jsoup.nodes.Document; 10 | import org.jsoup.nodes.Element; 11 | import org.jsoup.select.Elements; 12 | 13 | import java.io.IOException; 14 | 15 | public class GetDetails extends AsyncTask { 16 | 17 | private static String TAG = "GetDetails"; 18 | String newsUrl; 19 | String href; 20 | private OnTaskComplete onTaskComplete; 21 | 22 | public GetDetails(String href) { 23 | this.href = href; 24 | Log.i(TAG, "href: " + href); 25 | } 26 | 27 | public void setGetDetailsCompleteListener(OnTaskComplete onTaskComplete) { 28 | this.onTaskComplete = onTaskComplete; 29 | } 30 | 31 | @Override 32 | protected void onPreExecute() { 33 | super.onPreExecute(); 34 | } 35 | 36 | @Override 37 | protected DetailsObject doInBackground(Void... arg0) { 38 | DetailsObject detailsObject = new DetailsObject(); 39 | try { 40 | Document doc; 41 | Element infoHolder = null; 42 | 43 | if (!href.contains("newscenter")) { 44 | // get the newscenter url 45 | doc = Jsoup.connect("http://hubble.stsci.edu" + href).timeout(8 * 1000).get(); 46 | infoHolder = doc.getElementsByClass("info-holder").first(); 47 | } 48 | 49 | if (infoHolder != null) { 50 | newsUrl = infoHolder.attr("href"); 51 | } else { 52 | // probably from a redirect 53 | newsUrl = href; 54 | } 55 | Log.i(TAG, "newsUrl " + newsUrl); 56 | 57 | // with the new url then get the info 58 | doc = Jsoup.connect("http://hubble.stsci.edu" + newsUrl).get(); 59 | 60 | Elements p = doc.getElementsByTag("p"); 61 | detailsObject.setDescription(p.toString()); 62 | 63 | } catch (IOException e) { 64 | e.printStackTrace(); 65 | } 66 | return detailsObject; 67 | } 68 | 69 | @Override 70 | protected void onPostExecute(DetailsObject result) { 71 | onTaskComplete.setTaskComplete(result, newsUrl); 72 | } 73 | 74 | public interface OnTaskComplete { 75 | void setTaskComplete(DetailsObject result, String newsUrl); 76 | } 77 | 78 | } -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/utils/ImageUtils.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.utils; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.drawable.BitmapDrawable; 6 | import android.widget.ImageView; 7 | 8 | import com.derek_s.hubble_gallery.R; 9 | import com.derek_s.hubble_gallery.base.Constants; 10 | import com.derek_s.hubble_gallery.utils.ui.Toasty; 11 | 12 | import java.io.File; 13 | import java.io.FileNotFoundException; 14 | import java.io.FileOutputStream; 15 | import java.io.IOException; 16 | 17 | /** 18 | * Created by dereksmith on 15-04-11. 19 | */ 20 | public class ImageUtils { 21 | 22 | public static String saveImage(ImageView imageView, String imgUrl, Context context, boolean toastOnSuccess) { 23 | String savedUri = null; 24 | 25 | if (null != imgUrl && imgUrl.length() > 0) { 26 | int endIndex = imgUrl.lastIndexOf("/"); 27 | if (endIndex != -1) { 28 | imgUrl = imgUrl.substring(endIndex, imgUrl.length()); 29 | } 30 | } else { 31 | Toasty.show(context, R.string.error_saving_image, Toasty.LENGTH_LONG); 32 | return savedUri; 33 | } 34 | 35 | BitmapDrawable drawable = (BitmapDrawable) imageView.getDrawable(); 36 | Bitmap bitmap = drawable.getBitmap(); 37 | 38 | if (bitmap == null) { 39 | Toasty.show(context, R.string.error_saving_image, Toasty.LENGTH_LONG); 40 | return savedUri; 41 | } 42 | 43 | new File(Constants.imageDirectory()).mkdirs(); 44 | File image = new File(Constants.imageDirectory(), imgUrl); 45 | 46 | boolean success = false; 47 | // Encode the file as a PNG image. 48 | FileOutputStream outStream; 49 | try { 50 | 51 | outStream = new FileOutputStream(image); 52 | bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outStream); 53 | /* 100 to keep full quality of the image */ 54 | outStream.flush(); 55 | outStream.close(); 56 | success = true; 57 | } catch (FileNotFoundException e) { 58 | e.printStackTrace(); 59 | } catch (IOException e) { 60 | e.printStackTrace(); 61 | } 62 | 63 | if (success) { 64 | if (toastOnSuccess) 65 | Toasty.show(context, R.string.image_saved, Toasty.LENGTH_MEDIUM); 66 | return imgUrl; 67 | } else { 68 | Toasty.show(context, R.string.error_saving_image, Toasty.LENGTH_LONG); 69 | return null; 70 | } 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/ui/widgets/StretchyImageView.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.ui.widgets; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.ImageView; 6 | 7 | // This works around the issue described here: http://stackoverflow.com/a/12675430/265521 8 | public class StretchyImageView extends ImageView { 9 | 10 | public StretchyImageView(Context context) { 11 | super(context); 12 | } 13 | 14 | public StretchyImageView(Context context, AttributeSet attrs) { 15 | super(context, attrs); 16 | } 17 | 18 | public StretchyImageView(Context context, AttributeSet attrs, int defStyle) { 19 | super(context, attrs, defStyle); 20 | } 21 | 22 | @Override 23 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 24 | // Call super() so that resolveUri() is called. 25 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 26 | 27 | // If there's no drawable we can just use the result from super. 28 | if (getDrawable() == null) 29 | return; 30 | 31 | final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); 32 | final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); 33 | 34 | int w = getDrawable().getIntrinsicWidth(); 35 | int h = getDrawable().getIntrinsicHeight(); 36 | if (w <= 0) 37 | w = 1; 38 | if (h <= 0) 39 | h = 1; 40 | 41 | // Desired aspect ratio of the view's contents (not including padding) 42 | float desiredAspect = (float) w / (float) h; 43 | 44 | // We are allowed to change the view's width 45 | boolean resizeWidth = widthSpecMode != MeasureSpec.EXACTLY; 46 | 47 | // We are allowed to change the view's height 48 | boolean resizeHeight = heightSpecMode != MeasureSpec.EXACTLY; 49 | 50 | int pleft = getPaddingLeft(); 51 | int pright = getPaddingRight(); 52 | int ptop = getPaddingTop(); 53 | int pbottom = getPaddingBottom(); 54 | 55 | // Get the sizes that ImageView decided on. 56 | int widthSize = getMeasuredWidth(); 57 | int heightSize = getMeasuredHeight(); 58 | 59 | if (resizeWidth && !resizeHeight) { 60 | // Resize the width to the height, maintaining aspect ratio. 61 | int newWidth = (int) (desiredAspect * (heightSize - ptop - pbottom)) + pleft + pright; 62 | setMeasuredDimension(newWidth, heightSize); 63 | } else if (resizeHeight && !resizeWidth) { 64 | int newHeight = (int) ((widthSize - pleft - pright) / desiredAspect) + ptop + pbottom; 65 | setMeasuredDimension(widthSize, newHeight); 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/ui/adapters/MainGridAdapter.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.ui.adapters; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.ImageView; 10 | import android.widget.TextView; 11 | 12 | import com.derek_s.hubble_gallery.R; 13 | import com.derek_s.hubble_gallery._shared.model.TileObject; 14 | import com.derek_s.hubble_gallery.utils.ui.FontFactory; 15 | import com.squareup.picasso.Picasso; 16 | 17 | import java.util.ArrayList; 18 | 19 | import butterknife.Bind; 20 | import butterknife.ButterKnife; 21 | 22 | public class MainGridAdapter extends RecyclerView.Adapter { 23 | 24 | private static LayoutInflater inflater = null; 25 | public ArrayList mTiles; 26 | Context context; 27 | 28 | 29 | public MainGridAdapter(Activity activity, Context context) { 30 | 31 | this.mTiles = new ArrayList<>(); 32 | this.context = context; 33 | inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 34 | } 35 | 36 | 37 | @Override 38 | public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 39 | 40 | View view = inflater.inflate(R.layout.item_tile, parent, false); 41 | 42 | return new RecyclerViewHolder(view); 43 | } 44 | 45 | @Override 46 | public void onBindViewHolder(RecyclerViewHolder holder, int position) { 47 | 48 | holder.tvTitle.setTypeface(FontFactory.getCondensedRegular(context)); 49 | holder.tvTitle.setText(mTiles.get(position).getTitle()); 50 | Picasso.with(context).load(mTiles.get(position).getSrc()).into(holder.ivTile); 51 | 52 | } 53 | 54 | 55 | @Override 56 | public int getItemCount() { 57 | return mTiles.size(); 58 | } 59 | 60 | public void addItems(ArrayList tiles) { 61 | mTiles.addAll(tiles); 62 | notifyDataSetChanged(); 63 | } 64 | 65 | public void clear() { 66 | mTiles.clear(); 67 | notifyDataSetChanged(); 68 | } 69 | 70 | public TileObject getItemAtPosition(int position) { 71 | return mTiles.get(position); 72 | } 73 | 74 | public static class RecyclerViewHolder extends RecyclerView.ViewHolder { 75 | 76 | @Bind(R.id.iv_tile) 77 | ImageView ivTile; 78 | @Bind(R.id.tv_title) 79 | TextView tvTitle; 80 | 81 | public RecyclerViewHolder(View view) { 82 | super(view); 83 | ButterKnife.bind(this, view); 84 | } 85 | 86 | 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/derek_s/hubble_gallery/nav_drawer/dialog/DialogAbout.kt: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.nav_drawer.dialog 2 | 3 | import android.content.Context 4 | import android.content.pm.PackageInfo 5 | import android.text.Html 6 | import android.text.method.LinkMovementMethod 7 | import android.view.View 8 | import android.widget.TextView 9 | import com.afollestad.materialdialogs.MaterialDialog 10 | import com.afollestad.materialdialogs.Theme 11 | import com.derek_s.hubble_gallery.R 12 | import com.derek_s.hubble_gallery.utils.ui.FontFactory 13 | 14 | class DialogAbout(context: Context, listener: DialogAboutListener) { 15 | 16 | private val context: Context 17 | private val listener: DialogAboutListener 18 | private var dialog: MaterialDialog? = null 19 | 20 | private var tvTitle: TextView? = null 21 | private var tvVersion: TextView? = null 22 | private var tvBody: TextView? = null 23 | 24 | init { 25 | this.context = context 26 | this.listener = listener 27 | } 28 | 29 | fun getDialog(): MaterialDialog { 30 | if (dialog == null) { 31 | return MaterialDialog.Builder(context) 32 | .customView(R.layout.dialog_about, false) 33 | .backgroundColorRes(R.color.background) 34 | .theme(Theme.DARK) 35 | .forceStacking(true) 36 | .positiveText(context.resources.getString(R.string.show_intro)) 37 | .onPositive { materialDialog, dialogAction -> listener.onShowIntroClicked() } 38 | .build() 39 | } else { 40 | return dialog!! 41 | } 42 | } 43 | 44 | fun show() { 45 | dialog = getDialog(); 46 | dialog!!.show() 47 | 48 | findViews(dialog!!.customView) 49 | beautifyViews() 50 | 51 | var pInfo: PackageInfo = context.packageManager.getPackageInfo(context.getPackageName(), 0) 52 | var version = pInfo.versionName; 53 | tvVersion!!.text = "V " + version 54 | 55 | tvBody!!.movementMethod = LinkMovementMethod.getInstance() 56 | tvBody!!.text = removeHtmlBottomPadding(Html.fromHtml(context.resources.getString(R.string.about_body))) 57 | } 58 | 59 | private fun removeHtmlBottomPadding(mText: CharSequence?): CharSequence? { 60 | var text: CharSequence = mText ?: return null 61 | if (text.length == 0) 62 | return text 63 | 64 | while (text[text.length - 1] == '\n') { 65 | text = text.subSequence(0, text.length - 1) 66 | } 67 | return text 68 | } 69 | 70 | private fun findViews(dView: View?) { 71 | if (dView == null) 72 | return 73 | 74 | tvTitle = dView.findViewById(R.id.tv_title) as TextView 75 | tvVersion = dView.findViewById(R.id.tv_version) as TextView 76 | tvBody = dView.findViewById(R.id.tv_body) as TextView 77 | } 78 | 79 | private fun beautifyViews() { 80 | tvTitle!!.typeface = FontFactory.getCondensedRegular(context) 81 | tvVersion!!.typeface = FontFactory.getMedium(context) 82 | tvBody!!.typeface = FontFactory.getRegular(context) 83 | } 84 | } -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/api/GetAlbum.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.api; 2 | 3 | import android.os.AsyncTask; 4 | 5 | import com.derek_s.hubble_gallery._shared.model.TileObject; 6 | import com.derek_s.hubble_gallery.ui.fragments.FragMain; 7 | 8 | import org.jsoup.Jsoup; 9 | import org.jsoup.nodes.Document; 10 | import org.jsoup.nodes.Element; 11 | import org.jsoup.select.Elements; 12 | 13 | import java.io.IOException; 14 | import java.util.ArrayList; 15 | 16 | public class GetAlbum extends AsyncTask> { 17 | 18 | int limit; 19 | int page; 20 | String query; 21 | boolean hiRes = false; 22 | private OnTaskComplete onTaskComplete; 23 | 24 | public GetAlbum(int limit, int page, String query, boolean hiRes) { 25 | this.limit = limit; 26 | this.page = page; 27 | this.query = query; 28 | this.hiRes = hiRes; 29 | FragMain.currentPage = page; 30 | } 31 | 32 | public void setGetAlbumCompleteListener(OnTaskComplete onTaskComplete) { 33 | this.onTaskComplete = onTaskComplete; 34 | } 35 | 36 | @Override 37 | protected void onPreExecute() { 38 | super.onPreExecute(); 39 | } 40 | 41 | @Override 42 | protected ArrayList doInBackground(Void... arg0) { 43 | ArrayList mArray = new ArrayList<>(); 44 | try { 45 | Document doc = null; 46 | 47 | if (hiRes) { 48 | doc = Jsoup.connect("http://hubble.stsci.edu/gallery/album/" + query + "/npp/" + limit + "/hires/true/" + "+" + page).get(); 49 | } else { 50 | doc = Jsoup.connect("http://hubble.stsci.edu/gallery/album/" + query + "/npp/" + limit + "/" + "+" + page).get(); 51 | } 52 | Elements links = doc.select("div#ListBlock"); 53 | for (int i = 0; i < limit; i++) { 54 | try { 55 | Element link = links.select("a").get(i); 56 | Element img = link.select("img").first(); 57 | 58 | //Log.i("apod", "src: " + img.attr("src")); 59 | 60 | TileObject t = new TileObject(); 61 | t.setId(link.id()); 62 | t.setTitle(link.attr("title")); 63 | t.setHref(link.attr("href")); 64 | 65 | // uses higher res image for thumbnails 66 | String src = img.attr("src"); 67 | if (src.contains(".gif")) 68 | src = src.replace(".gif", ".jpg"); 69 | src = src.replace("-thumb", "-web"); 70 | 71 | t.setSrc(src); 72 | 73 | mArray.add(t); 74 | } catch (IndexOutOfBoundsException e) { 75 | // stop the iteration 76 | i = limit; 77 | } 78 | } 79 | 80 | } catch (IOException e) { 81 | e.printStackTrace(); 82 | } 83 | return mArray; 84 | } 85 | 86 | @Override 87 | protected void onPostExecute(ArrayList result) { 88 | onTaskComplete.setTaskComplete(result); 89 | } 90 | 91 | public interface OnTaskComplete { 92 | void setTaskComplete(ArrayList result); 93 | } 94 | 95 | 96 | } -------------------------------------------------------------------------------- /app/src/main/res-navigation/layout/item_footer_nav_drawer.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 20 | 21 | 33 | 34 | 42 | 43 | 44 | 45 | 49 | 50 | 62 | 63 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/utils/Animation/SquareFlipper.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.utils.Animation; 2 | 3 | import android.graphics.Camera; 4 | import android.graphics.Matrix; 5 | import android.view.View; 6 | import android.view.animation.Animation; 7 | import android.view.animation.DecelerateInterpolator; 8 | import android.view.animation.Transformation; 9 | 10 | import com.daimajia.androidanimations.library.Techniques; 11 | import com.daimajia.androidanimations.library.YoYo; 12 | 13 | public class SquareFlipper { 14 | boolean stop = false; 15 | boolean justStarted = false; 16 | private View flippingView; 17 | private FlipAnimator flipAnimator; 18 | 19 | public void startAnimation(final View view) { 20 | if (flipAnimator != null) { 21 | flipAnimator.cancel(); 22 | flipAnimator = null; 23 | } 24 | stop = false; 25 | justStarted = true; 26 | flippingView = view; 27 | flippingView.setVisibility(View.VISIBLE); 28 | flippingView.setAlpha(0); 29 | 30 | flipAnimator = new FlipAnimator(); 31 | flipAnimator.setDuration(600); 32 | flipAnimator.setRepeatCount(-1); 33 | flipAnimator.setFillAfter(true); 34 | flipAnimator.setInterpolator(new DecelerateInterpolator()); 35 | view.startAnimation(flipAnimator); 36 | } 37 | 38 | public void stopAnimation() { 39 | stop = true; 40 | } 41 | 42 | public class FlipAnimator extends Animation { 43 | 44 | private Camera camera; 45 | private float centerX; 46 | private float centerY; 47 | 48 | public FlipAnimator() { 49 | setFillAfter(true); 50 | } 51 | 52 | @Override 53 | public void initialize(int width, int height, int parentWidth, int parentHeight) { 54 | super.initialize(width, height, parentWidth, parentHeight); 55 | camera = new Camera(); 56 | this.centerX = width / 2; 57 | this.centerY = height / 2; 58 | } 59 | 60 | @Override 61 | protected void applyTransformation(float interpolatedTime, Transformation t) { 62 | // Angle around the y-axis of the rotation at the given time. It is 63 | // calculated both in radians and in the equivalent degrees. 64 | final double radians = Math.PI * interpolatedTime; 65 | float degrees = (float) (180.0 * radians / Math.PI); 66 | 67 | if (interpolatedTime > 0.4 && interpolatedTime < 0.6) { 68 | if (justStarted) { 69 | flippingView.setAlpha(1.0f); 70 | YoYo.with(Techniques.FadeIn).duration(200).playOn(flippingView); 71 | justStarted = false; 72 | } else if (stop) { 73 | flippingView.setVisibility(View.INVISIBLE); 74 | flippingView.clearAnimation(); 75 | } 76 | } 77 | 78 | final Matrix matrix = t.getMatrix(); 79 | 80 | camera.save(); 81 | camera.translate(0.0f, 0.0f, (float) (150.0 * Math.sin(radians))); 82 | camera.rotateX(true ? degrees : 0); 83 | camera.getMatrix(matrix); 84 | camera.restore(); 85 | 86 | matrix.preTranslate(-centerX, -centerY); 87 | matrix.postTranslate(centerX, centerY); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/utils/ui/starfield/Stars.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.utils.ui.starfield; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Paint; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Iterator; 8 | import java.util.Random; 9 | 10 | public class Stars { 11 | public static final int LEFT = 0; 12 | public static final int RIGHT = 1; 13 | public static final int RANDOM = 2; 14 | private final ArrayList poss; 15 | private final ArrayList old; 16 | private float size; 17 | private float speed; 18 | private int number; 19 | private Random r = new Random(); 20 | private int mWidth, mHeight; 21 | 22 | public Stars(float size, float speed, int number, int width, int height) { 23 | this.size = size; 24 | this.speed = speed; 25 | this.number = number; 26 | mWidth = width; 27 | mHeight = height; 28 | 29 | poss = new ArrayList(); 30 | old = new ArrayList(); 31 | } 32 | 33 | public void step(int direction) { 34 | if (r.nextInt(number) == 0) { 35 | int size = old.size(); 36 | if (size > 0) { 37 | poss.add(old.remove(size - 1)); 38 | } else { 39 | if (direction == RANDOM) { 40 | direction = r.nextInt(RANDOM); // Random direction 41 | } 42 | poss.add(new Pos(-1, 0, direction)); 43 | } 44 | } 45 | int width = mWidth; 46 | int height = mHeight; 47 | 48 | synchronized (poss) { 49 | Iterator itr = poss.iterator(); 50 | while (itr.hasNext()) { 51 | Pos pos = itr.next(); 52 | 53 | switch (pos.mDirection) { 54 | case RIGHT: 55 | if (pos.x > width) { 56 | pos.x = -1; 57 | old.add(pos); 58 | itr.remove(); 59 | continue; 60 | } 61 | 62 | if (pos.x < 0) { 63 | pos.x = 0; 64 | pos.y = r.nextInt() % height; 65 | } 66 | break; 67 | case LEFT: 68 | if (pos.x < 0) { 69 | pos.x = mWidth + 1; 70 | old.add(pos); 71 | itr.remove(); 72 | continue; 73 | } 74 | 75 | if (pos.x > mWidth) { 76 | pos.x = mWidth; 77 | pos.y = r.nextInt() % height; 78 | } 79 | break; 80 | } 81 | pos.updatePos(speed); 82 | } 83 | } 84 | } 85 | 86 | public void draw(Canvas c, int width, int offset, Paint p) { 87 | for (Pos pos : poss) { 88 | if (pos.x + size > offset && pos.x < offset + width) { 89 | c.drawRect(pos.x - offset, pos.y, pos.x - offset + size, pos.y + size, p); 90 | } 91 | } 92 | } 93 | 94 | private static class Pos { 95 | private float x, y; 96 | private int mDirection; 97 | 98 | public Pos(float x, float y, int direction) { 99 | this.x = x; 100 | this.y = y; 101 | mDirection = direction; 102 | } 103 | 104 | public void updatePos(float move) { 105 | switch (mDirection) { 106 | case RIGHT: 107 | x += move; 108 | break; 109 | case LEFT: 110 | x -= move; 111 | break; 112 | } 113 | } 114 | } 115 | } -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/utils/svg/SvgHelper.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.utils.svg; 2 | 3 | /** 4 | * Created by dereksmith on 15-05-04. 5 | */ 6 | 7 | import android.content.Context; 8 | import android.graphics.Canvas; 9 | import android.graphics.Matrix; 10 | import android.graphics.Paint; 11 | import android.graphics.Path; 12 | import android.graphics.PathMeasure; 13 | import android.graphics.Rect; 14 | import android.graphics.RectF; 15 | import android.graphics.Region; 16 | import android.util.Log; 17 | 18 | import com.caverock.androidsvg.PreserveAspectRatio; 19 | import com.caverock.androidsvg.SVG; 20 | import com.caverock.androidsvg.SVGParseException; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | public class SvgHelper { 26 | private static final String LOG_TAG = "SVG"; 27 | 28 | private final List mPaths = new ArrayList(); 29 | private final Paint mSourcePaint; 30 | 31 | private SVG mSvg; 32 | 33 | public SvgHelper(Paint sourcePaint) { 34 | mSourcePaint = sourcePaint; 35 | } 36 | 37 | public void load(Context context, int svgResource) { 38 | if (mSvg != null) return; 39 | try { 40 | mSvg = SVG.getFromResource(context, svgResource); 41 | mSvg.setDocumentPreserveAspectRatio(PreserveAspectRatio.UNSCALED); 42 | } catch (SVGParseException e) { 43 | Log.e(LOG_TAG, "Could not load specified SVG resource", e); 44 | } 45 | } 46 | 47 | public List getPathsForViewport(final int width, final int height) { 48 | mPaths.clear(); 49 | 50 | Canvas canvas = new Canvas() { 51 | private final Matrix mMatrix = new Matrix(); 52 | 53 | @Override 54 | public int getWidth() { 55 | return width; 56 | } 57 | 58 | @Override 59 | public int getHeight() { 60 | return height; 61 | } 62 | 63 | @Override 64 | public void drawPath(Path path, Paint paint) { 65 | Path dst = new Path(); 66 | 67 | //noinspection deprecation 68 | getMatrix(mMatrix); 69 | path.transform(mMatrix, dst); 70 | 71 | mPaths.add(new SvgPath(dst, new Paint(mSourcePaint))); 72 | } 73 | }; 74 | 75 | RectF viewBox = mSvg.getDocumentViewBox(); 76 | float scale = Math.min(width / viewBox.width(), height / viewBox.height()); 77 | 78 | canvas.translate( 79 | (width - viewBox.width() * scale) / 2.0f, 80 | (height - viewBox.height() * scale) / 2.0f); 81 | canvas.scale(scale, scale); 82 | 83 | mSvg.renderToCanvas(canvas); 84 | 85 | return mPaths; 86 | } 87 | 88 | public static class SvgPath { 89 | private static final Region sRegion = new Region(); 90 | private static final Region sMaxClip = new Region( 91 | Integer.MIN_VALUE, Integer.MIN_VALUE, 92 | Integer.MAX_VALUE, Integer.MAX_VALUE); 93 | 94 | final Path path; 95 | final Path renderPath = new Path(); 96 | final Paint paint; 97 | final float length; 98 | final Rect bounds; 99 | final PathMeasure measure; 100 | 101 | SvgPath(Path path, Paint paint) { 102 | this.path = path; 103 | this.paint = paint; 104 | 105 | measure = new PathMeasure(path, false); 106 | this.length = measure.getLength(); 107 | 108 | sRegion.setPath(path, sMaxClip); 109 | bounds = sRegion.getBounds(); 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/ui/fragments/FragWelcomeInfo.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.ui.fragments; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.text.Html; 6 | import android.text.method.LinkMovementMethod; 7 | import android.util.Log; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.TextView; 12 | 13 | import com.derek_s.hubble_gallery.R; 14 | import com.derek_s.hubble_gallery.base.FragBase; 15 | import com.derek_s.hubble_gallery.home.ActHome; 16 | import com.derek_s.hubble_gallery.utils.ui.FontFactory; 17 | 18 | import butterknife.Bind; 19 | import butterknife.ButterKnife; 20 | 21 | public class FragWelcomeInfo extends FragBase { 22 | private static final String CURRENT_PAGE = "current_page"; 23 | private static String TAG = "FragWelcomeInfo"; 24 | private static String PAGE_KEY = "page_number"; 25 | private static int pagePos = 1; 26 | @Bind(R.id.tv_welcome_info) 27 | TextView tvInfo; 28 | @Bind(R.id.tv_enter) 29 | TextView tvEnter; 30 | 31 | public static FragWelcomeInfo newInstance(int position) { 32 | final FragWelcomeInfo fragment = new FragWelcomeInfo(); 33 | // Supply int position as an argument. 34 | Bundle args = new Bundle(); 35 | args.putInt(PAGE_KEY, position); 36 | fragment.setArguments(args); 37 | 38 | return fragment; 39 | } 40 | 41 | @Override 42 | public void onCreate(Bundle savedInstanceState) { 43 | super.onCreate(savedInstanceState); 44 | if (savedInstanceState == null) { 45 | pagePos = getArguments() != null ? getArguments().getInt(PAGE_KEY) : 1; 46 | } else { 47 | pagePos = savedInstanceState.getInt(CURRENT_PAGE); 48 | } 49 | } 50 | 51 | @Override 52 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 53 | Bundle savedInstanceState) { 54 | View rootView = inflater.inflate(R.layout.frag_welcome_info, container, false); 55 | ButterKnife.bind(this, rootView); 56 | 57 | tvInfo.setTypeface(FontFactory.getCondensedRegular(getActivity())); 58 | tvInfo.setVisibility(View.VISIBLE); 59 | tvEnter.setVisibility(View.INVISIBLE); 60 | 61 | Log.i(TAG, "onCreateView pagePos = " + pagePos); 62 | 63 | switch (pagePos) { 64 | case (1): 65 | tvInfo.setText(getActivity().getResources().getText(R.string.info_1)); 66 | break; 67 | case (2): 68 | tvInfo.setText(getActivity().getResources().getText(R.string.info_2)); 69 | break; 70 | case (3): 71 | tvInfo.setText(Html.fromHtml(getActivity().getResources().getString(R.string.info_3))); 72 | tvInfo.setMovementMethod(LinkMovementMethod.getInstance()); 73 | break; 74 | case (4): 75 | tvInfo.setVisibility(View.INVISIBLE); 76 | tvEnter.setTypeface(FontFactory.getCondensedLight(getActivity())); 77 | tvEnter.setVisibility(View.VISIBLE); 78 | tvEnter.setOnClickListener(new View.OnClickListener() { 79 | @Override 80 | public void onClick(View v) { 81 | Intent i = new Intent(getActivity(), ActHome.class); 82 | i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); 83 | startActivity(i); 84 | getActivity().overridePendingTransition(android.R.anim.fade_in, R.anim.zoom_in_exit); 85 | } 86 | }); 87 | break; 88 | } 89 | 90 | return rootView; 91 | } 92 | 93 | @Override 94 | public void onSaveInstanceState(Bundle outState) { 95 | outState.putInt(CURRENT_PAGE, pagePos); 96 | super.onSaveInstanceState(outState); 97 | } 98 | 99 | 100 | } -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/utils/ui/starfield/StarField.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.utils.ui.starfield; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Color; 5 | import android.graphics.Paint; 6 | import android.os.Handler; 7 | import android.view.SurfaceHolder; 8 | 9 | public class StarField { 10 | 11 | private static final int TILES_NORMAL = 1; 12 | private static final int TILES_LARGE = 5; 13 | private static final int TILES_HUGE = 7; 14 | private static final float AMMOUNT_FEW = 3f; 15 | private static final float AMMOUNT_NORMAL = 2f; 16 | private static final float AMMOUNT_LOTS = 0.2f; 17 | Paint mPaintFill = new Paint(); 18 | Paint mPaintStar = new Paint(); 19 | Paint mPaintText = new Paint(); 20 | private String TAG = getClass().getSimpleName(); 21 | private SurfaceHolder surfaceHolder; 22 | private boolean mVisible = true; 23 | private Handler mHandler = new Handler(); 24 | private int mWidth, mHeight, xWidth; 25 | private int mOffsetSpan; 26 | private int mOffset = 1; 27 | private int mTiles = TILES_NORMAL; 28 | private int mDirection = Stars.RIGHT; 29 | private float mAmmount = AMMOUNT_NORMAL; 30 | private Stars[] stars; 31 | private boolean firstTime = true; 32 | private Runnable mDraw = new Runnable() { 33 | @Override 34 | public void run() { 35 | drawFrame(); 36 | } 37 | }; 38 | 39 | public StarField(SurfaceHolder surfaceHolder, int mWidth, int mHeight) { 40 | this.surfaceHolder = surfaceHolder; 41 | 42 | this.mWidth = mWidth; 43 | this.mHeight = mHeight; 44 | 45 | mPaintFill.setStyle(Paint.Style.FILL); 46 | mPaintFill.setColor(Color.BLACK); 47 | 48 | mPaintStar.setStyle(Paint.Style.FILL); 49 | mPaintStar.setColor(Color.WHITE); 50 | mPaintStar.setAntiAlias(true); 51 | } 52 | 53 | public void start() { 54 | drawFrame(); 55 | } 56 | 57 | public void stop() { 58 | mVisible = false; 59 | mHandler.removeCallbacks(mDraw); 60 | } 61 | 62 | private void updateXWidthAndOffsetSpan() { 63 | xWidth = mWidth * mTiles; 64 | mOffsetSpan = mWidth * (mTiles - 1); 65 | } 66 | 67 | private void drawFrame() { 68 | Canvas c = null; 69 | if (firstTime) { 70 | firstTime = false; 71 | updateXWidthAndOffsetSpan(); 72 | try { 73 | c = surfaceHolder.lockCanvas(); 74 | if (c != null) { 75 | c.drawRect(0, 0, mWidth, mHeight, mPaintFill); 76 | c.drawText("Loading", 5, 75, mPaintText); 77 | } 78 | } finally { 79 | if (c != null) surfaceHolder.unlockCanvasAndPost(c); 80 | c = null; 81 | } 82 | Stars far = new Stars(1f, 1f, Math.round(3 * mAmmount), xWidth, mHeight); 83 | Stars middle = new Stars(2.1f, 1.5f, Math.round(5 * mAmmount), xWidth, mHeight); 84 | Stars near = new Stars(2.9f, 2.5f, Math.round(7 * mAmmount), xWidth, mHeight); 85 | Stars close = new Stars(4f, 15f, Math.round(40 * mAmmount), xWidth, mHeight); 86 | 87 | stars = new Stars[]{far, middle, near, close}; 88 | 89 | int steps = mWidth * 2; 90 | for (Stars star : stars) { 91 | for (int i = 0; i < steps; i++) { 92 | star.step(mDirection); 93 | } 94 | } 95 | } 96 | 97 | try { 98 | c = surfaceHolder.lockCanvas(); 99 | if (c != null) { 100 | c.drawRect(0, 0, mWidth, mHeight, mPaintFill); 101 | 102 | for (Stars star : stars) { 103 | star.step(mDirection); 104 | star.draw(c, mWidth, mOffset, mPaintStar); 105 | } 106 | } 107 | } finally { 108 | if (c != null) surfaceHolder.unlockCanvasAndPost(c); 109 | } 110 | 111 | mHandler.removeCallbacks(mDraw); 112 | if (mVisible) { 113 | mHandler.postDelayed(mDraw, 40); 114 | } 115 | } 116 | } -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 16 | 17 | 18 | 23 | 24 | 27 | 28 | 31 | 32 | 35 | 36 | 37 | 38 | 44 | 45 | 51 | 52 | 56 | 57 | 61 | 62 | 66 | 67 | 71 | 72 | 76 | 77 | 81 | 82 | 86 | 87 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/ui/activities/ActWelcome.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.ui.activities; 2 | 3 | import android.graphics.Color; 4 | import android.graphics.Point; 5 | import android.os.Build; 6 | import android.os.Bundle; 7 | import android.support.v4.app.Fragment; 8 | import android.view.Display; 9 | import android.view.SurfaceView; 10 | import android.view.View; 11 | import android.view.Window; 12 | import android.view.WindowManager; 13 | import android.widget.RelativeLayout; 14 | 15 | import com.derek_s.hubble_gallery.R; 16 | import com.derek_s.hubble_gallery.base.ActBase; 17 | import com.derek_s.hubble_gallery.internal.di.ActivityComponent; 18 | import com.derek_s.hubble_gallery.ui.adapters.OnboardingFragmentPager; 19 | import com.derek_s.hubble_gallery.utils.ui.starfield.StarField; 20 | 21 | import butterknife.Bind; 22 | import butterknife.ButterKnife; 23 | import fr.castorflex.android.verticalviewpager.VerticalViewPager; 24 | 25 | public class ActWelcome extends ActBase { 26 | 27 | @Bind(R.id.rl_onboarding) 28 | RelativeLayout rlOnboarding; 29 | @Bind(R.id.sv_starfield) 30 | SurfaceView svStarfield; 31 | @Bind(R.id.vertical_pager) 32 | VerticalViewPager verticalViewPager; 33 | int width; 34 | int height; 35 | boolean fromOnCreate = false; 36 | private StarField starField; 37 | 38 | @Override 39 | protected void onCreate(Bundle savedInstanceState) { 40 | super.onCreate(savedInstanceState); 41 | fromOnCreate = true; 42 | setContentView(R.layout.act_welcome); 43 | ButterKnife.bind(this); 44 | 45 | setWindowAttributes(); 46 | setWindowSizes(); 47 | 48 | starField = new StarField(svStarfield.getHolder(), width, height); 49 | starField.start(); 50 | 51 | // remove all fragments from manager 52 | if (getSupportFragmentManager().getFragments() != null) 53 | for (Fragment fragment : getSupportFragmentManager().getFragments()) { 54 | getSupportFragmentManager().beginTransaction().remove(fragment).commit(); 55 | } 56 | 57 | verticalViewPager.setAdapter(new OnboardingFragmentPager(getSupportFragmentManager())); 58 | verticalViewPager.setOffscreenPageLimit(5); 59 | } 60 | 61 | @Override 62 | public void onPause() { 63 | starField.stop(); 64 | super.onPause(); 65 | } 66 | 67 | @Override 68 | public void onResume() { 69 | if (fromOnCreate) { 70 | fromOnCreate = false; 71 | } else { 72 | setWindowSizes(); 73 | starField = new StarField(svStarfield.getHolder(), width, height); 74 | starField.start(); 75 | } 76 | super.onResume(); 77 | } 78 | 79 | private void setWindowSizes() { 80 | Display display = getWindowManager().getDefaultDisplay(); 81 | Point size = new Point(); 82 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 83 | display.getRealSize(size); 84 | } else { 85 | display.getSize(size); 86 | } 87 | width = size.x; 88 | height = size.y; 89 | } 90 | 91 | private void setWindowAttributes() { 92 | Window window = getWindow(); 93 | 94 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 95 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 96 | window.setStatusBarColor(Color.TRANSPARENT); 97 | window.setNavigationBarColor(Color.TRANSPARENT); 98 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 99 | window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); 100 | window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 101 | } 102 | 103 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 104 | getWindow().getDecorView().setSystemUiVisibility( 105 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE 106 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 107 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); 108 | } 109 | } 110 | 111 | @Override 112 | protected void injectComponent(ActivityComponent activityComponent) { 113 | activityComponent.inject(this); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/derek_s/hubble_gallery/nav_drawer/adapters/GroupViewHolder.kt: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.nav_drawer.adapters 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import android.os.Build 6 | import android.support.v4.content.ContextCompat 7 | import android.view.LayoutInflater 8 | import android.view.View 9 | import android.view.ViewGroup 10 | import android.view.animation.RotateAnimation 11 | import android.widget.ImageView 12 | import android.widget.TextView 13 | import butterknife.bindView 14 | import com.bignerdranch.expandablerecyclerview.ViewHolder.ParentViewHolder 15 | import com.derek_s.hubble_gallery.R 16 | import com.derek_s.hubble_gallery.nav_drawer.model.SectionChildObject 17 | import com.derek_s.hubble_gallery.utils.ui.FontFactory 18 | 19 | class GroupViewHolder private constructor(itemView: View) : ParentViewHolder(itemView) { 20 | 21 | val tvTitle: TextView by bindView(R.id.tv_title) 22 | val ivExpand: ImageView by bindView(R.id.iv_expand) 23 | 24 | private val INITIAL_POSITION = 0.0f 25 | private val ROTATED_POSITION = 180f 26 | 27 | init { 28 | beautifyViews() 29 | } 30 | 31 | fun beautifyViews() { 32 | tvTitle.typeface = FontFactory.getMedium(itemView.context) 33 | } 34 | 35 | fun onBind(item: NavigationAdapterItem, listener: NavDrawerAdapter.NavAdapterListener, 36 | pos: Int, selectedQuery: String) { 37 | var section: SectionChildObject = item.`object` as SectionChildObject 38 | 39 | if (section.query.equals(selectedQuery)) { 40 | tvTitle.setBackgroundColor(ContextCompat.getColor(itemView.context, R.color.focused_color)); 41 | tvTitle.setTextColor(ContextCompat.getColor(itemView.context, R.color.seleted_item_color)); 42 | } else { 43 | tvTitle.setBackgroundResource(R.drawable.selector_default); 44 | tvTitle.setTextColor(ContextCompat.getColor(itemView.context, R.color.body_dark_theme)); 45 | } 46 | 47 | tvTitle.text = section.sectionTitle 48 | tvTitle.setOnClickListener { 49 | listener.onSectionClicked(section) 50 | listener.setSelectedQuery(section.query) 51 | tvTitle.setBackgroundColor(ContextCompat.getColor(itemView.context, R.color.focused_color)); 52 | tvTitle.setTextColor(ContextCompat.getColor(itemView.context, R.color.seleted_item_color)); 53 | } 54 | 55 | if (item.childObjectList == null) { 56 | ivExpand.visibility = View.GONE 57 | } else { 58 | ivExpand.visibility = View.VISIBLE 59 | ivExpand.setOnClickListener { 60 | if (isExpanded) { 61 | collapseView() 62 | } else { 63 | expandView() 64 | } 65 | } 66 | } 67 | } 68 | 69 | @SuppressLint("NewApi") 70 | override fun setExpanded(expanded: Boolean) { 71 | super.setExpanded(expanded) 72 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 73 | if (expanded) { 74 | ivExpand.rotation = ROTATED_POSITION 75 | } else { 76 | ivExpand.rotation = INITIAL_POSITION 77 | } 78 | } 79 | } 80 | 81 | override fun onExpansionToggled(expanded: Boolean) { 82 | super.onExpansionToggled(expanded) 83 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 84 | val rotateAnimation: RotateAnimation 85 | if (expanded) { 86 | // rotate clockwise 87 | rotateAnimation = RotateAnimation(ROTATED_POSITION, 88 | INITIAL_POSITION, 89 | RotateAnimation.RELATIVE_TO_SELF, 0.5f, 90 | RotateAnimation.RELATIVE_TO_SELF, 0.5f) 91 | } else { 92 | // rotate counterclockwise 93 | rotateAnimation = RotateAnimation(-1 * ROTATED_POSITION, 94 | INITIAL_POSITION, 95 | RotateAnimation.RELATIVE_TO_SELF, 0.5f, 96 | RotateAnimation.RELATIVE_TO_SELF, 0.5f) 97 | } 98 | 99 | rotateAnimation.duration = 200 100 | rotateAnimation.fillAfter = true 101 | ivExpand.startAnimation(rotateAnimation) 102 | } 103 | } 104 | 105 | override fun shouldItemViewClickToggleExpansion(): Boolean { 106 | return false 107 | } 108 | 109 | companion object { 110 | fun create(context: Context, viewGroup: ViewGroup): GroupViewHolder { 111 | return GroupViewHolder(LayoutInflater.from(context).inflate(R.layout.item_group, 112 | viewGroup, false)) 113 | } 114 | } 115 | 116 | 117 | } 118 | -------------------------------------------------------------------------------- /app/src/main/res-details/layout/act_details.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 16 | 17 | 23 | 24 | 33 | 34 | 35 | 36 | 44 | 45 | 59 | 60 | 68 | 69 | 85 | 86 | 87 | 88 | 89 | 90 | 100 | 101 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | maven { url 'https://maven.fabric.io/public' } 4 | mavenCentral() 5 | } 6 | 7 | dependencies { 8 | //noinspection GradleDynamicVersion 9 | classpath 'io.fabric.tools:gradle:1.+' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | apply plugin: 'com.android.application' 15 | apply plugin: 'kotlin-android' 16 | apply plugin: 'io.fabric' 17 | 18 | repositories { 19 | maven { url 'https://maven.fabric.io/public' } 20 | maven { url "https://jitpack.io" } 21 | mavenCentral() 22 | } 23 | 24 | kapt { 25 | generateStubs = true 26 | } 27 | 28 | android { 29 | compileSdkVersion 23 30 | buildToolsVersion "23.0.3" 31 | 32 | def verName = "1.5.1" 33 | def verCode = 21 34 | 35 | defaultConfig { 36 | applicationId 'com.derek_s.hubble_gallery' 37 | minSdkVersion 16 38 | targetSdkVersion 22 39 | versionCode verCode 40 | versionName verName 41 | multiDexEnabled = true 42 | } 43 | 44 | buildTypes { 45 | release { 46 | minifyEnabled false 47 | } 48 | } 49 | 50 | sourceSets { 51 | main.res.srcDirs = ['src/main/res', 52 | 'src/main/res-details', 53 | 'src/main/res-navigation', 54 | 'src/main/res-welcome'] 55 | main.java.srcDirs = ['src/main/kotlin', 56 | 'src/main/java'] 57 | } 58 | 59 | packagingOptions { 60 | exclude 'META-INF/DEPENDENCIES.txt' 61 | exclude 'META-INF/LICENSE.txt' 62 | exclude 'META-INF/NOTICE.txt' 63 | exclude 'META-INF/NOTICE' 64 | exclude 'META-INF/LICENSE' 65 | exclude 'META-INF/DEPENDENCIES' 66 | exclude 'META-INF/notice.txt' 67 | exclude 'META-INF/license.txt' 68 | exclude 'META-INF/dependencies.txt' 69 | exclude 'META-INF/LGPL2.1' 70 | exclude 'AndroidManifest.xml' 71 | exclude 'META-INF/services/javax.annotation.processing.Processor' 72 | } 73 | 74 | lintOptions { 75 | disable 'InvalidPackage' 76 | } 77 | } 78 | 79 | dependencies { 80 | compile fileTree(dir: 'libs', include: ['*.jar']) 81 | 82 | // Google - Android 83 | compile "com.android.support:support-v4:$android_support_version" 84 | compile "com.android.support:appcompat-v7:$android_support_version" 85 | compile "com.android.support:palette-v7:$android_support_version" 86 | compile "com.android.support:multidex:$multidex_version" 87 | 88 | // kotlin related 89 | compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 90 | provided "org.glassfish:javax.annotation:$javaxannotations_version" 91 | 92 | // general 93 | compile "com.google.dagger:dagger:$dagger_version" 94 | kapt "com.google.dagger:dagger-compiler:$dagger_version" 95 | compile "com.jakewharton:kotterknife:$kotterknife_version" 96 | compile "com.jakewharton:butterknife:$butterknife_version" 97 | kapt "com.jakewharton:butterknife:$butterknife_version" 98 | compile "com.google.code.gson:gson:$gson_version" 99 | compile "com.squareup.picasso:picasso:$picasso_version" 100 | compile "com.nineoldandroids:library:$nineoldandroids_version" 101 | provided "javax.annotation:jsr250-api:$jsr250_version" 102 | provided "org.projectlombok:lombok:$lombok_version" 103 | kapt "org.projectlombok:lombok:$lombok_version" 104 | 105 | // network 106 | compile "org.jsoup:jsoup:$jsoup_version" 107 | 108 | // UI 109 | compile "com.bignerdranch.android:expandablerecyclerview:$expandablerecycler_version" 110 | compile "com.github.ksoichiro:android-observablescrollview:$observablescrollview_version" 111 | compile "com.daimajia.easing:library:$daimajiaeasing_version" 112 | compile "com.daimajia.androidanimations:library:$androidanimations_version" 113 | compile "com.github.johnpersano:supertoasts:$supertoasts_version" 114 | compile "com.github.castorflex.verticalviewpager:library:$verticalviewpager_version" 115 | compile "com.caverock:androidsvg:$androidsvg_version" 116 | compile("com.github.afollestad.material-dialogs:core:$materialdialogs_version") { 117 | transitive = true 118 | } 119 | 120 | compile("com.crashlytics.sdk.android:crashlytics:$crashlytics_version") { 121 | transitive = true; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/utils/ui/FontFactory.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.utils.ui; 2 | 3 | import android.content.Context; 4 | import android.graphics.Typeface; 5 | 6 | import com.derek_s.hubble_gallery.R; 7 | 8 | /** 9 | * Created by dereksmith on 15-03-07. 10 | */ 11 | public class FontFactory { 12 | 13 | /* 14 | To use: tv1.setTypeface(FontFactory.getRegular(getContext()); 15 | */ 16 | 17 | private static Typeface t1; 18 | private static Typeface t2; 19 | private static Typeface t3; 20 | private static Typeface t4; 21 | private static Typeface t5; 22 | private static Typeface t6; 23 | private static Typeface t7; 24 | private static Typeface t8; 25 | private static Typeface t9; 26 | private static Typeface t10; 27 | private static Typeface t11; 28 | private static Typeface t12; 29 | private static Typeface t13; 30 | private static Typeface t14; 31 | private static Typeface t15; 32 | private static Typeface t16; 33 | private static Typeface t17; 34 | private static Typeface t18; 35 | 36 | public static Typeface getBlack(Context c) { 37 | if (t1 == null) { 38 | t1 = Typeface.createFromAsset(c.getAssets(), c.getString(R.string.roboto_black)); 39 | } 40 | return t1; 41 | } 42 | 43 | public static Typeface getBlackItalic(Context c) { 44 | if (t2 == null) { 45 | t2 = Typeface.createFromAsset(c.getAssets(), c.getString(R.string.roboto_black_italic)); 46 | } 47 | return t2; 48 | } 49 | 50 | public static Typeface getBold(Context c) { 51 | if (t3 == null) { 52 | t3 = Typeface.createFromAsset(c.getAssets(), c.getString(R.string.roboto_bold)); 53 | } 54 | return t3; 55 | } 56 | 57 | public static Typeface getBoldItalic(Context c) { 58 | if (t4 == null) { 59 | t4 = Typeface.createFromAsset(c.getAssets(), c.getString(R.string.roboto_bold_italic)); 60 | } 61 | return t4; 62 | } 63 | 64 | public static Typeface getItalic(Context c) { 65 | if (t5 == null) { 66 | t5 = Typeface.createFromAsset(c.getAssets(), c.getString(R.string.roboto_italic)); 67 | } 68 | return t5; 69 | } 70 | 71 | public static Typeface getLight(Context c) { 72 | if (t6 == null) { 73 | t6 = Typeface.createFromAsset(c.getAssets(), c.getString(R.string.roboto_light)); 74 | } 75 | return t6; 76 | } 77 | 78 | public static Typeface getLightItalic(Context c) { 79 | if (t7 == null) { 80 | t7 = Typeface.createFromAsset(c.getAssets(), c.getString(R.string.roboto_light_italic)); 81 | } 82 | return t7; 83 | } 84 | 85 | public static Typeface getMedium(Context c) { 86 | if (t8 == null) { 87 | t8 = Typeface.createFromAsset(c.getAssets(), c.getString(R.string.roboto_medium)); 88 | } 89 | return t8; 90 | } 91 | 92 | public static Typeface getMediumItalic(Context c) { 93 | if (t9 == null) { 94 | t9 = Typeface.createFromAsset(c.getAssets(), c.getString(R.string.roboto_medium_italic)); 95 | } 96 | return t9; 97 | } 98 | 99 | public static Typeface getRegular(Context c) { 100 | if (t10 == null) { 101 | t10 = Typeface.createFromAsset(c.getAssets(), c.getString(R.string.roboto_regular)); 102 | } 103 | return t10; 104 | } 105 | 106 | public static Typeface getThin(Context c) { 107 | if (t11 == null) { 108 | t11 = Typeface.createFromAsset(c.getAssets(), c.getString(R.string.roboto_thin)); 109 | } 110 | return t11; 111 | } 112 | 113 | public static Typeface getThinItalic(Context c) { 114 | if (t12 == null) { 115 | t12 = Typeface.createFromAsset(c.getAssets(), c.getString(R.string.roboto_thin_italic)); 116 | } 117 | return t12; 118 | } 119 | 120 | public static Typeface getCondensedBold(Context c) { 121 | if (t13 == null) { 122 | t13 = Typeface.createFromAsset(c.getAssets(), c.getString(R.string.roboto_condensed_bold)); 123 | } 124 | return t13; 125 | } 126 | 127 | public static Typeface getCondensedBoldItalic(Context c) { 128 | if (t14 == null) { 129 | t14 = Typeface.createFromAsset(c.getAssets(), c.getString(R.string.roboto_condensed_bold_italic)); 130 | } 131 | return t14; 132 | } 133 | 134 | public static Typeface getCondensedItalic(Context c) { 135 | if (t15 == null) { 136 | t15 = Typeface.createFromAsset(c.getAssets(), c.getString(R.string.roboto_condensed_italic)); 137 | } 138 | return t15; 139 | } 140 | 141 | public static Typeface getCondensedLight(Context c) { 142 | if (t16 == null) { 143 | t16 = Typeface.createFromAsset(c.getAssets(), c.getString(R.string.roboto_condensed_light)); 144 | } 145 | return t16; 146 | } 147 | 148 | public static Typeface getCondensedLightItalic(Context c) { 149 | if (t17 == null) { 150 | t17 = Typeface.createFromAsset(c.getAssets(), c.getString(R.string.roboto_condensed_light_italic)); 151 | } 152 | return t17; 153 | } 154 | 155 | public static Typeface getCondensedRegular(Context c) { 156 | if (t18 == null) { 157 | t18 = Typeface.createFromAsset(c.getAssets(), c.getString(R.string.roboto_condensed_regular)); 158 | } 159 | return t18; 160 | } 161 | 162 | } -------------------------------------------------------------------------------- /app/src/main/res/values-de/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hubble Gallerie 4 | Über 5 | Zu Favoriten hinzufügen 6 | Link kopieren 7 | Dummy Knopf 8 | Eintreten 9 | Fehler beim Laden des Bildes 10 | Fehler beim Speichern des Bildes 11 | Favoriten 12 | Beste Auflösung 13 | Vollbild 14 | Bilder gespeichert in /Pictures/Hubble 15 | Das Weltraumteleskop \"Hubble\" wurde 1990 in eine niedrige Erdumlaufbahn (low earth orbit) gestartet. Es ist bis heute in Betrieb. Hubble verfügt über ein 2,4-Meter-Spiegelteleskop uns über vier Hauptinstrumente, die im nahen Ultraviolettbereich, im infraroten Himmelsbeobachtungen ermöglichen. 16 | Hubbles Umlaufbahn befindet sich außerhalb der Erdatmosphäre, so dass atmosphärische Aberrationen entfallen. Dies ermöglicht äußerst hochauflösende Aufnahmen mit vernachlässigbarem Hintergrundleuchten. Hubble hat einige der detailreichsten Aufnahmen im sichtbaren Wellenlängenbereich gemacht über die wir bis heute verfügen. Hubble erlaubt damit Tiefe Einblicke in Raum und Zeit. Zahlreiche Beobachtungen von Hubble haben zu Durchbrüchen in der Astrophysik geführt, so konnte bspw. die Expansionsrate des Universums sehr genau bestimmt werden. 17 | Am beliebtesten 18 | Schließen 19 | Öffnen 20 | Kein Internetzugriff 21 | Im Browser öffnen 22 | 23 | Neu laden 24 | Aus Favoriten entfernen 25 | Erneut versuchen 26 | Bild speichern 27 | Herunterscrollen 28 | Suchen 29 | 30 | Bild teilen 31 | Link teilen 32 | Einführung anzeigen 33 | Sortiere nach 34 | Quelltext zeigen 35 | Details 36 | Bildbetrachter 37 | Willkommen 38 | Entdecke Bilder und speichere sie als Favorit. Sie werden dann hier erscheinen. 39 | Du hast bisher keine Favoriten gesetzt. 40 | Ich bin sicher, du findest einige Favoriten! 43 | Entwickelt von Derek Smith, 44 | folge mir auf Twitter @drkcsm, um \"Hallo\" zu sagen. Oder noch besser: Schicke mir etwas Taschengeld anpaypal.me/derekcsm 45 | und hilf mit, dass dieses Projekt weitergeführt wird! <3 46 |

47 | 48 |

49 | Beiträge von: 50 |
51 | - PedroVictorB 52 |

53 | 54 |
55 | 56 |

57 | Hubble Gallerie ist ein Open Source Projekt 58 | github.com/derekcsm/hubble_gallery 59 | Bewertungen im Play Store sind willkommen! Wenn Du daran interessiert bist, etwas zu dem Projekt beizutragen wäre das klasse! 60 | Bitte beachte die Richtlinien in README und ich werde Deinen Beitrag in das Projekt aufnehmen. 61 |

62 | 63 |

64 | Der Inhalt dieser App wird bereitgestellt von HubbleSite, 65 | betrieben vom Space Telescope Science Institute\'s Office of Public Outreach. 66 |

67 | 68 |

69 | Diese ist keine offizielle App. Es besteht keinerlei Verbindung zu NASA oder JPL. 70 | Der gesamte Quellcode dieses Projektes wurde lizenziert unter der 71 | Apache License Version 2.0. 72 |

73 | 74 | ]]>
75 | Open Source Projekt. Entwickelt von@drkcsm. 77 | Wenn Du in Spendierlaune bist, sende etwas Taschengeld an paypal.me/derekcsm und hilf, das Projekt am Laugen zu halten! ]]> 78 |
-------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/ui/widgets/PopOutCircularProgressDrawable.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.ui.widgets; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorListenerAdapter; 5 | import android.animation.ObjectAnimator; 6 | import android.graphics.Canvas; 7 | import android.graphics.Color; 8 | import android.graphics.Paint; 9 | import android.graphics.Rect; 10 | import android.view.animation.AccelerateDecelerateInterpolator; 11 | 12 | /** 13 | * @author Hannes Dorfmann 14 | */ 15 | public class PopOutCircularProgressDrawable extends CircularProgressDrawable { 16 | 17 | // TODO make private and final 18 | public static float POPOUT_SHOW_DURATION = 800; 19 | public static float POPOUT_HIDE_DURATION = ANGLE_ANIMATOR_DURATION; 20 | 21 | private boolean mPopOut = true; 22 | private int mPopOutColor; 23 | private float mTargetRadius; 24 | private float mCurrentRadius; 25 | private float mCircleCenterX; 26 | private float mCircleCenterY; 27 | private ObjectAnimator mShowPopOutAnimator; 28 | private ObjectAnimator mHidePopOutAnimator; 29 | private float mProgress = 0f; 30 | private int mHidePopOutProgress = 255; 31 | private boolean mPopOutComplete = false; 32 | private boolean mPopOutFading = true; 33 | private boolean mOriginalPopOutFading; 34 | private Paint mPaint = new Paint(); 35 | 36 | public PopOutCircularProgressDrawable(int popOutColor, int[] colors, float strokeWidth, 37 | float popOutStrokeWidth, float speed, int minSweepAngle, int maxSweepAngle, 38 | boolean popOutFading, Style style) { 39 | 40 | super(colors, strokeWidth, speed, minSweepAngle, maxSweepAngle, style); 41 | mPopOutColor = popOutColor; 42 | mPopOutFading = popOutFading; 43 | mOriginalPopOutFading = popOutFading; 44 | mPaint.setAntiAlias(true); 45 | mPaint.setStyle(Paint.Style.STROKE); 46 | mPaint.setStrokeWidth(popOutStrokeWidth); 47 | mPaint.setColor(mPopOutColor); 48 | 49 | int diff = (int) ((popOutStrokeWidth - strokeWidth) / 2 + 0.5f); 50 | 51 | setCirclePadding(diff, diff, diff, diff); 52 | } 53 | 54 | @Override 55 | protected void onBoundsChange(Rect bounds) { 56 | super.onBoundsChange(bounds); 57 | 58 | mCircleCenterX = bounds.exactCenterX(); 59 | mCircleCenterY = bounds.exactCenterY(); 60 | mTargetRadius = (bounds.height() - mPaint.getStrokeWidth()) / 2; 61 | } 62 | 63 | public int getPopOutColor() { 64 | return mPaint.getColor(); 65 | } 66 | 67 | public PopOutCircularProgressDrawable setPopOutColor(int color) { 68 | mPopOutColor = color; 69 | mPaint.setColor(color); 70 | return this; 71 | } 72 | 73 | public PopOutCircularProgressDrawable setPopOut(boolean enabled) { 74 | mPopOut = enabled; 75 | return this; 76 | } 77 | 78 | public boolean isPopOutEnabled() { 79 | return mPopOut; 80 | } 81 | 82 | @Override 83 | public void reset() { 84 | super.reset(); 85 | mPopOutComplete = false; 86 | mCurrentRadius = 0; 87 | mPaint.setAlpha(255); 88 | mPaint.setColor(mPopOutColor); 89 | mPopOutFading = mOriginalPopOutFading; 90 | } 91 | 92 | 93 | private void startPopOutAnimation() { 94 | stop(); 95 | 96 | mShowPopOutAnimator = 97 | ObjectAnimator.ofFloat(this, "progress", 0f, 1f).setDuration( 98 | (int) (POPOUT_SHOW_DURATION / getSpeed() + 0.5)); 99 | mShowPopOutAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); 100 | 101 | mShowPopOutAnimator.addListener(new AnimatorListenerAdapter() { 102 | @Override 103 | public void onAnimationCancel(Animator animation) { 104 | reset(); 105 | } 106 | 107 | @Override 108 | public void onAnimationEnd(Animator animation) { 109 | startCircleAndPopHiding(); 110 | } 111 | }); 112 | 113 | mShowPopOutAnimator.start(); 114 | } 115 | 116 | @Override 117 | public void draw(Canvas canvas) { 118 | super.draw(canvas); 119 | canvas.drawCircle(mCircleCenterX, mCircleCenterY, mCurrentRadius, mPaint); 120 | } 121 | 122 | public float getProgress() { 123 | return mProgress; 124 | } 125 | 126 | @Override 127 | public void setProgress(float progress) { 128 | mProgress = progress; 129 | 130 | if (mPopOutFading) { 131 | int targetAlpha = Color.alpha(mPopOutColor); 132 | int currentAlpha = (int) (mapPoint(progress, 0, 0.85f, targetAlpha / 10, targetAlpha) + 0.5); 133 | mPaint.setAlpha(currentAlpha); 134 | if (currentAlpha >= targetAlpha) { 135 | mPopOutFading = false; 136 | } 137 | } 138 | 139 | mCurrentRadius = mapPoint(progress, 0, 1, 0, mTargetRadius); 140 | if (progress == 1f) { 141 | mPopOutComplete = true; 142 | } 143 | invalidateSelf(); 144 | } 145 | 146 | public float getHidePopOut() { 147 | return mHidePopOutProgress; 148 | } 149 | 150 | public void setHidePopOut(int progress) { 151 | mHidePopOutProgress = progress; 152 | mPaint.setAlpha(progress); 153 | invalidateSelf(); 154 | } 155 | 156 | protected void startCircleAndPopHiding() { 157 | super.start(); 158 | mHidePopOutAnimator = 159 | ObjectAnimator.ofInt(this, "hidePopOut", Color.alpha(mPopOutColor), 0).setDuration( 160 | (int) (POPOUT_HIDE_DURATION / getSpeed() + 0.5f)); 161 | 162 | mHidePopOutAnimator.addListener(new AnimatorListenerAdapter() { 163 | @Override 164 | public void onAnimationCancel(Animator animation) { 165 | reset(); 166 | } 167 | }); 168 | mHidePopOutAnimator.start(); 169 | } 170 | 171 | @Override 172 | public void start() { 173 | if (!mPopOutComplete) { 174 | startPopOutAnimation(); 175 | } else { 176 | startCircleAndPopHiding(); 177 | } 178 | } 179 | 180 | @Override 181 | public void stop() { 182 | if (mShowPopOutAnimator != null) { 183 | mShowPopOutAnimator.cancel(); 184 | } 185 | 186 | if (mHidePopOutAnimator != null) { 187 | mHidePopOutAnimator.cancel(); 188 | } 189 | 190 | super.stop(); 191 | } 192 | } -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hubble Gallery 5 | Hubble 6 | Welcome 7 | 8 | 9 | Favorites 10 | Search 11 | About 12 | Review & share 13 | 14 | Sort by 15 | Most popular 16 | Highest resolution 17 | Details 18 | 19 | 20 | Set image as… 21 | Share image 22 | Save image 23 | Open in browser 24 | Share link 25 | Copy link 26 | Add to favorites 27 | Remove from favorites 28 | 29 | Error during image saving 30 | Image saved to /Pictures/Hubble 31 | Show image fullscreen 32 | 33 | 34 | Explore and favorite images, they\'ll show up here 35 | You have no favorites… yet 36 | I\'m sure you\'ll find some favorites! 37 | 38 | 39 | No internet connection 40 | Retry 41 | Reload 42 | Error loading image 43 | 44 | 45 | Scroll down 46 | Enter 47 | The Hubble Space Telescope was launched into 48 | low Earth orbit in 1990, and remains in operation. With a 2.4-meter (7.9 ft) mirror, Hubble\'s 49 | four main instruments observe in the near ultraviolet, visible, and near infrared spectra. 50 | 51 | Hubble\'s orbit outside the distortion of Earth\'s atmosphere allows it to take 52 | extremely high-resolution images with negligible background light. Hubble has recorded some of 53 | the most detailed visible-light images ever, allowing a deep view into space and time. Many 54 | Hubble observations have led to breakthroughs in astrophysics, such as accurately determining 55 | the rate of expansion of the universe. 56 | 57 | open source project. 61 | Maintained by @drkcsm. If you\'re feeling generous, 62 | send some grocery money to paypal.me/derekcsm 63 | to help keep this project going! 64 | ]]> 65 | 66 | 67 | Built by — 68 | View source code 69 | Show intro 70 | 73 | Maintained by Derek Smith, 74 | follow me on Twitter @drkcsm to say hi. Or 75 | even better, send some grocery money to paypal.me/derekcsm 76 | to help keep this project going! <3 77 |

78 | 79 |

80 | Contributions from: 81 |
82 | - PedroVictorB 83 |

84 | 85 |
86 | 87 |

88 | Hubble gallery is an open source project 89 | github.com/derekcsm/hubble_gallery 90 | stars are much appreciated. If you\'re interested in contributing that\'s awesome! Please see 91 | the README guidelines and I\'d be more than happy to help merge your PR into the project. 92 |

93 | 94 |

95 | The content showcased in this app comes from HubbleSite, 96 | run by the Space Telescope Science Institute\'s Office of Public Outreach. 97 |

98 | 99 |

100 | This is not an official app, I have no affiliation with NASA or JPL. All source code for 101 | this project is licensed under the 102 | Apache License Version 2.0. 103 |

104 | 105 | ]]>
106 | 107 | 108 | fonts/Roboto-Black.ttf 109 | fonts/Roboto-BlackItalic.ttf 110 | fonts/Roboto-Bold.ttf 111 | fonts/Roboto-BoldItalic.ttf 112 | fonts/Roboto-Regular.ttf 113 | fonts/Roboto-Thin.ttf 114 | fonts/Roboto-ThinItalic.ttf 115 | fonts/Roboto-Italic.ttf 116 | fonts/Roboto-Light.ttf 117 | fonts/Roboto-LightItalic.ttf 118 | fonts/Roboto-Medium.ttf 119 | fonts/Roboto-MediumItalic.ttf 120 | 121 | fonts/RobotoCondensed-Bold.ttf 122 | fonts/RobotoCondensed-BoldItalic.ttf 123 | fonts/RobotoCondensed-Italic.ttf 124 | fonts/RobotoCondensed-Light.ttf 125 | fonts/RobotoCondensed-LightItalic.ttf 126 | fonts/RobotoCondensed-Regular.ttf 127 | 128 | Open 129 | Close 130 | 131 | ImageViewer 132 | Dummy Button 133 | DUMMY\nCONTENT 134 | 135 |
136 | -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/ui/widgets/CircleProgressView.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.ui.widgets; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.drawable.Drawable; 8 | import android.os.Parcel; 9 | import android.os.Parcelable; 10 | import android.util.AttributeSet; 11 | import android.util.DisplayMetrics; 12 | import android.view.View; 13 | 14 | import com.derek_s.hubble_gallery.R; 15 | 16 | 17 | /** 18 | * Simplest custom view possible, using CircularProgressDrawable 19 | */ 20 | public class CircleProgressView extends View { 21 | 22 | private CircularProgressDrawable mDrawable; 23 | 24 | public CircleProgressView(Context context) { 25 | this(context, null); 26 | } 27 | 28 | public CircleProgressView(Context context, AttributeSet attrs) { 29 | this(context, attrs, 0); 30 | } 31 | 32 | public CircleProgressView(Context context, AttributeSet attrs, int defStyleAttr) { 33 | super(context, attrs, defStyleAttr); 34 | init(context, attrs, defStyleAttr); 35 | } 36 | 37 | private void init(Context context, AttributeSet attrs, int defStyleAttr) { 38 | 39 | TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CircleProgressView); 40 | 41 | int color = a.getColor(R.styleable.CircleProgressView_cpvColor, Color.LTGRAY); 42 | 43 | int popOutColor = a.getColor(R.styleable.CircleProgressView_cpvPopOutColor, 0); 44 | 45 | // The colors 46 | int colorsId = a.getResourceId(R.styleable.CircleProgressView_cpvColors, 0); 47 | 48 | // The stroke size 49 | int strokeSize = 50 | a.getDimensionPixelSize(R.styleable.CircleProgressView_cpvStrokeWidth, dpToPx(context, 5)); 51 | 52 | // popOut stroke width 53 | int popOutStrokeWidth = 54 | a.getDimensionPixelSize(R.styleable.CircleProgressView_cpvPopOutStrokeWidth, 55 | dpToPx(context, 7)); 56 | 57 | // How long should it take to make a complete circle 58 | int circleAnimDuration = a.getInt(R.styleable.CircleProgressView_cpvCircleAnimDuration, 2000); 59 | 60 | // How long should it take to sweep the tail 61 | int sweepAnimDuration = a.getInt(R.styleable.CircleProgressView_cpvSweepAnimDuration, 600); 62 | 63 | float speed = a.getFloat(R.styleable.CircleProgressView_cpvSpeed, 1.0f); 64 | 65 | int minSweepAngle = a.getInteger(R.styleable.CircleProgressView_cpvMinSweepAngle, 20); 66 | int maxSweepAngle = a.getInteger(R.styleable.CircleProgressView_cpvMaxSweepAngle, 300); 67 | 68 | a.recycle(); 69 | 70 | int[] colors = null; 71 | if (colorsId != 0) { 72 | colors = context.getResources().getIntArray(colorsId); 73 | } 74 | 75 | if (colors == null) { 76 | colors = new int[1]; 77 | colors[0] = color; 78 | } 79 | 80 | if (popOutColor == 0) { 81 | // No Popout 82 | mDrawable = 83 | new CircularProgressDrawable(colors, (float) strokeSize, speed, minSweepAngle, 84 | maxSweepAngle, CircularProgressDrawable.Style.ROUNDED); 85 | } else { 86 | // Use PopOut 87 | mDrawable = 88 | new PopOutCircularProgressDrawable(popOutColor, colors, (float) strokeSize, 89 | popOutStrokeWidth, speed, minSweepAngle, maxSweepAngle, true, 90 | CircularProgressDrawable.Style.ROUNDED); 91 | } 92 | mDrawable.setCallback(this); 93 | } 94 | 95 | public int dpToPx(Context context, int dp) { 96 | DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); 97 | return (int) ((dp * displayMetrics.density) + 0.5); 98 | } 99 | 100 | @Override 101 | protected void onVisibilityChanged(View changedView, int visibility) { 102 | super.onVisibilityChanged(changedView, visibility); 103 | 104 | if (mDrawable == null) { 105 | return; 106 | } 107 | 108 | if (visibility == VISIBLE) { 109 | mDrawable.start(); 110 | } else { 111 | mDrawable.stop(); 112 | } 113 | } 114 | 115 | @Override 116 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 117 | super.onSizeChanged(w, h, oldw, oldh); 118 | mDrawable.setBounds(0, 0, w, h); 119 | } 120 | 121 | @Override 122 | public void draw(Canvas canvas) { 123 | super.draw(canvas); 124 | mDrawable.draw(canvas); 125 | } 126 | 127 | @Override 128 | protected boolean verifyDrawable(Drawable who) { 129 | return who == mDrawable || super.verifyDrawable(who); 130 | } 131 | 132 | @Override 133 | protected void onDetachedFromWindow() { 134 | super.onDetachedFromWindow(); 135 | mDrawable.stop(); 136 | } 137 | 138 | 139 | /* 140 | * @Override public Parcelable onSaveInstanceState() { //begin boilerplate code that allows parent 141 | * classes to save state Parcelable superState = super.onSaveInstanceState(); 142 | * 143 | * SavedState ss = new SavedState(superState); //end 144 | * 145 | * ss.color = mDrawable.getColor(); ss.sweepAnimDuration = mDrawable.getSweepAnimationDuration(); 146 | * ss.circleAnimDuration = mDrawable.getCircleAnimationDuration(); ss.strokeSize = 147 | * mDrawable.getStrokeWidth(); 148 | * 149 | * return ss; } 150 | * 151 | * @Override public void onRestoreInstanceState(Parcelable state) { //begin boilerplate code so 152 | * parent classes can restore state if(!(state instanceof SavedState)) { 153 | * super.onRestoreInstanceState(state); return; } 154 | * 155 | * SavedState ss = (SavedState)state; super.onRestoreInstanceState(ss.getSuperState()); //end 156 | * 157 | * mDrawable.setCircleAnimationDuration(ss.circleAnimDuration); 158 | * mDrawable.setSweepAnimationDuration(ss.sweepAnimDuration); mDrawable.setColor(ss.color); 159 | * mDrawable.setStrokeWidth(ss.strokeSize); } 160 | */ 161 | 162 | static class SavedState extends BaseSavedState { 163 | // required field that makes Parcelables from a Parcel 164 | public static final Creator CREATOR = 165 | new Creator() { 166 | public SavedState createFromParcel(Parcel in) { 167 | return new SavedState(in); 168 | } 169 | 170 | public SavedState[] newArray(int size) { 171 | return new SavedState[size]; 172 | } 173 | }; 174 | int color; 175 | float strokeSize; 176 | int circleAnimDuration; 177 | int sweepAnimDuration; 178 | 179 | SavedState(Parcelable superState) { 180 | super(superState); 181 | } 182 | 183 | private SavedState(Parcel in) { 184 | super(in); 185 | this.color = in.readInt(); 186 | this.strokeSize = in.readFloat(); 187 | this.circleAnimDuration = in.readInt(); 188 | this.sweepAnimDuration = in.readInt(); 189 | } 190 | 191 | @Override 192 | public void writeToParcel(Parcel out, int flags) { 193 | super.writeToParcel(out, flags); 194 | out.writeInt(this.color); 195 | out.writeFloat(this.strokeSize); 196 | out.writeInt(this.circleAnimDuration); 197 | out.writeInt(this.sweepAnimDuration); 198 | } 199 | } 200 | } -------------------------------------------------------------------------------- /app/src/main/java/com/derek_s/hubble_gallery/utils/svg/SvgView.java: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.utils.svg; 2 | 3 | /** 4 | * Created by dereksmith on 15-05-04. 5 | */ 6 | 7 | import android.animation.ObjectAnimator; 8 | import android.content.Context; 9 | import android.content.res.TypedArray; 10 | import android.graphics.Canvas; 11 | import android.graphics.DashPathEffect; 12 | import android.graphics.Paint; 13 | import android.graphics.PathEffect; 14 | import android.util.AttributeSet; 15 | import android.util.Log; 16 | import android.view.View; 17 | import android.view.animation.LinearInterpolator; 18 | 19 | import com.derek_s.hubble_gallery.R; 20 | 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | 24 | @SuppressWarnings({"ForLoopReplaceableByForEach", "UnusedDeclaration"}) 25 | public class SvgView extends View { 26 | private static final String LOG_TAG = "IntroView"; 27 | 28 | private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 29 | 30 | private final SvgHelper mSvg = new SvgHelper(mPaint); 31 | private final Object mSvgLock = new Object(); 32 | private int mSvgResource; 33 | private List mPaths = new ArrayList<>(0); 34 | private Thread mLoader; 35 | 36 | private float mPhase; 37 | private float mWait; 38 | private float mDrag; 39 | 40 | private int mDuration; 41 | private float mFadeFactor; 42 | 43 | private int mRadius; 44 | 45 | private ObjectAnimator mSvgAnimator; 46 | private ObjectAnimator mWaitAnimator; 47 | 48 | private OnReadyListener mListener; 49 | 50 | public SvgView(Context context, AttributeSet attrs) { 51 | this(context, attrs, 0); 52 | } 53 | 54 | public SvgView(Context context, AttributeSet attrs, int defStyle) { 55 | super(context, attrs, defStyle); 56 | 57 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.IntroView, defStyle, 0); 58 | try { 59 | if (a != null) { 60 | mPaint.setStrokeWidth(a.getFloat(R.styleable.IntroView_strokeWidth, 1.0f)); 61 | mPaint.setColor(a.getColor(R.styleable.IntroView_strokeColor, 0xff000000)); 62 | mPhase = a.getFloat(R.styleable.IntroView_phase, 1.0f); 63 | mDuration = a.getInt(R.styleable.IntroView_duration, 4000); 64 | mFadeFactor = a.getFloat(R.styleable.IntroView_fadeFactor, 10.0f); 65 | mRadius = a.getDimensionPixelSize(R.styleable.IntroView_waitRadius, 50); 66 | } 67 | } finally { 68 | if (a != null) a.recycle(); 69 | } 70 | 71 | init(); 72 | } 73 | 74 | private static PathEffect createPathEffect(float pathLength, float phase, float offset) { 75 | return new DashPathEffect(new float[]{pathLength, pathLength}, 76 | Math.max(phase * pathLength, offset)); 77 | } 78 | 79 | private void init() { 80 | mPaint.setStyle(Paint.Style.STROKE); 81 | 82 | // Note: using a software layer here is an optimization. This view works with 83 | // hardware accelerated rendering but every time a path is modified (when the 84 | // dash path effect is modified), the graphics pipeline will rasterize the path 85 | // again in a new texture. Since we are dealing with dozens of paths, it is much 86 | // more efficient to rasterize the entire view into a single re-usable texture 87 | // instead. Ideally this should be toggled using a heuristic based on the number 88 | // and or dimensions of paths to render. 89 | // Note that PathDashPathEffects can lead to clipping issues with hardware rendering. 90 | setLayerType(LAYER_TYPE_SOFTWARE, null); 91 | 92 | mSvgAnimator = ObjectAnimator.ofFloat(this, "phase", 0.0f, 1.0f).setDuration(mDuration); 93 | 94 | mWaitAnimator = ObjectAnimator.ofFloat(this, "wait", 1.0f, 0.0f).setDuration(mDuration); 95 | mWaitAnimator.setRepeatMode(ObjectAnimator.RESTART); 96 | mWaitAnimator.setRepeatCount(ObjectAnimator.INFINITE); 97 | mWaitAnimator.setInterpolator(new LinearInterpolator()); 98 | mWaitAnimator.start(); 99 | } 100 | 101 | public void setSvgResource(int resource) { 102 | if (mSvgResource == 0) { 103 | mSvgResource = resource; 104 | } 105 | } 106 | 107 | @Override 108 | protected void onDraw(Canvas canvas) { 109 | super.onDraw(canvas); 110 | 111 | synchronized (mSvgLock) { 112 | canvas.save(); 113 | canvas.translate(getPaddingLeft(), getPaddingTop() - getPaddingBottom()); 114 | final int count = mPaths.size(); 115 | for (int i = 0; i < count; i++) { 116 | SvgHelper.SvgPath svgPath = mPaths.get(i); 117 | 118 | // We use the fade factor to speed up the alpha animation 119 | int alpha = (int) (Math.min(mPhase * mFadeFactor, 1.0f) * 255.0f); 120 | svgPath.paint.setAlpha(alpha); 121 | 122 | canvas.drawPath(svgPath.renderPath, svgPath.paint); 123 | } 124 | canvas.restore(); 125 | } 126 | 127 | canvas.save(); 128 | canvas.translate(0.0f, getHeight() - getPaddingBottom() - mRadius * 3.0f); 129 | 130 | canvas.restore(); 131 | } 132 | 133 | @Override 134 | protected void onSizeChanged(final int w, final int h, int oldw, int oldh) { 135 | super.onSizeChanged(w, h, oldw, oldh); 136 | 137 | if (mLoader != null) { 138 | try { 139 | mLoader.join(); 140 | } catch (InterruptedException e) { 141 | Log.e(LOG_TAG, "Unexpected error", e); 142 | } 143 | } 144 | 145 | mLoader = new Thread(new Runnable() { 146 | @Override 147 | public void run() { 148 | mSvg.load(getContext(), mSvgResource); 149 | synchronized (mSvgLock) { 150 | mPaths = mSvg.getPathsForViewport( 151 | w - getPaddingLeft() - getPaddingRight(), 152 | h - getPaddingTop() - getPaddingBottom()); 153 | updatePathsPhaseLocked(); 154 | } 155 | post(new Runnable() { 156 | @Override 157 | public void run() { 158 | invokeReadyListener(); 159 | if (mSvgAnimator.isRunning()) mSvgAnimator.cancel(); 160 | mSvgAnimator.start(); 161 | } 162 | }); 163 | } 164 | }, "SVG Loader"); 165 | mLoader.start(); 166 | } 167 | 168 | private void invokeReadyListener() { 169 | if (mListener != null) mListener.onReady(); 170 | } 171 | 172 | public void setOnReadyListener(OnReadyListener listener) { 173 | mListener = listener; 174 | } 175 | 176 | private void updatePathsPhaseLocked() { 177 | final int count = mPaths.size(); 178 | for (int i = 0; i < count; i++) { 179 | SvgHelper.SvgPath svgPath = mPaths.get(i); 180 | svgPath.renderPath.reset(); 181 | svgPath.measure.getSegment(0.0f, svgPath.length * mPhase, svgPath.renderPath, true); 182 | // Required only for Android 4.4 and earlier 183 | svgPath.renderPath.rLineTo(0.0f, 0.0f); 184 | } 185 | } 186 | 187 | public float getPhase() { 188 | return mPhase; 189 | } 190 | 191 | public void setPhase(float phase) { 192 | mPhase = phase; 193 | synchronized (mSvgLock) { 194 | updatePathsPhaseLocked(); 195 | } 196 | invalidate(); 197 | } 198 | 199 | public float getWait() { 200 | return mWait; 201 | } 202 | 203 | public void setWait(float wait) { 204 | mWait = wait; 205 | 206 | invalidate(); 207 | } 208 | 209 | public interface OnReadyListener { 210 | void onReady(); 211 | } 212 | 213 | 214 | } -------------------------------------------------------------------------------- /app/src/main/res/values-fr/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Gallerie Hubble 5 | Hubble 6 | Bienvenue 7 | 8 | 9 | Favoris 10 | Chercher 11 | À Propos 12 | Noter et Partager 13 | 14 | Ranger 15 | Les + populaires d\'abord 16 | Les + hautes résolutions d\'abord 17 | Détails 18 | 19 | 20 | Définir comme… 21 | Partager l\'image 22 | Sauvegarder l\'image 23 | Ouvrir dans le navigateur 24 | Partager le lien 25 | Copier le lien 26 | Ajouter aux favoris 27 | Effacer des favoris 28 | 29 | Erreur lors de la sauvegarde de l\'image 30 | Image sauvegarée à /Pictures/Hubble 31 | Montrer l\'image en plein écran 32 | 33 | 34 | Découvrez et mettez en favoris des images, elles seront affichées ici 35 | Vous n\'avez aucune image favorite pour l\'instant 36 | Je suis sûr que vous trouverez des images favorites dans la collection! 37 | 38 | 39 | Pas de connection Internet 40 | Réessayez 41 | Rechargez 42 | Erreur lors du chargement de l\'image 43 | 44 | 45 | Faites glisser vers le haut 46 | Entrer 47 | Le Téléscope Spacial Hubble a été lancé en orbite terrienne basse en 1990, 48 | et est actuellement toujours en service. Avec un miroir de 2,4 mètres (7.9 pieds), les quatre principaux instruments de 49 | Hubble font des mesures et observent aux alentours de l\'ultraviolet, du visible et des spectres infrarouges. 50 | 51 | L\'orbite de Hubble se trouve en dehors du champ de distorsion de l\'atmosphère terrestre lui permet de 52 | prendre des images en très grande résolution avec une lumière de fond négligeable. Hubble a enregistré quelques-unes des 53 | images les plus détaillées visibles à l\'oeil nu jamais enregistrées, ceci permettant d\'avoir une image précie de 54 | l\'espace et du temps. Les observations via Hubble ont permis des découvertes capitales en astrophysique, comme le calcul 55 | précis de la vitesse d\'expansion de l\'univers. 56 | 57 | projet open source. 61 | Maintenu par @drkcsm. Si vous vous sentez généreux, 62 | faites un petit don à paypal.me/derekcsm 63 | pour aider ce projet à continuer d\'exister! 64 | ]]> 65 | 66 | 67 | Développé par — 68 | Voir le code source 69 | Jouer l\'intro 70 | 72 | Maintenu par Derek Smith, 73 | suivez moi sur Twitter @drkcsm pour me faire un petit coucou. Ou encore 74 | mieux, faites un petit don à paypal.me/derekcsm 75 | pour aider ce projet à continuer d\'exister! <3 76 |

77 |

78 | Contributions de : 79 |
80 | - PedroVictorB 81 |

82 |
83 |

84 | Gallerie Hubble est un projet open source 85 | github.com/derekcsm/hubble_gallery 86 | la mise en favoris est très appréciée. Si vous voulez contribuer, SUPER!! Veuillez lire le guide dans 87 | le README et je serais plus que content d\'inclure vos PR dans le projet. 88 |

89 |

90 | Le contenu de cette application vient de HubbleSite.org, 91 | site hébergé par le Space Telescope Science Institute\'s Office of Public Outreach. 92 |

93 |

94 | Ce n\'est pas une application officielle, je n\'ai aucune affiliation avec la NASA ou le JPL. Tout le code source de 95 | ce projet est licencié sous les termes de la 96 | Licence Apache Version 2.0. 97 |

98 | ]]>
99 | 100 | 101 | fonts/Roboto-Black.ttf 102 | fonts/Roboto-BlackItalic.ttf 103 | fonts/Roboto-Bold.ttf 104 | fonts/Roboto-BoldItalic.ttf 105 | fonts/Roboto-Regular.ttf 106 | fonts/Roboto-Thin.ttf 107 | fonts/Roboto-ThinItalic.ttf 108 | fonts/Roboto-Italic.ttf 109 | fonts/Roboto-Light.ttf 110 | fonts/Roboto-LightItalic.ttf 111 | fonts/Roboto-Medium.ttf 112 | fonts/Roboto-MediumItalic.ttf 113 | 114 | fonts/RobotoCondensed-Bold.ttf 115 | fonts/RobotoCondensed-BoldItalic.ttf 116 | fonts/RobotoCondensed-Italic.ttf 117 | fonts/RobotoCondensed-Light.ttf 118 | fonts/RobotoCondensed-LightItalic.ttf 119 | fonts/RobotoCondensed-Regular.ttf 120 | 121 | Ouvrir 122 | Fermer 123 | 124 | ImageViewer 125 | Dummy Button 126 | DUMMY\nCONTENT 127 | 128 |
129 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/derek_s/hubble_gallery/nav_drawer/presenters/NavigationPresenter.kt: -------------------------------------------------------------------------------- 1 | package com.derek_s.hubble_gallery.nav_drawer.presenters 2 | 3 | import android.content.Context 4 | import android.os.Bundle 5 | import android.support.v7.widget.LinearLayoutManager 6 | import com.bignerdranch.expandablerecyclerview.Model.ParentListItem 7 | import com.derek_s.hubble_gallery.nav_drawer.adapters.NavDrawerAdapter 8 | import com.derek_s.hubble_gallery.nav_drawer.adapters.NavigationAdapterItem 9 | import com.derek_s.hubble_gallery.nav_drawer.model.SectionChildObject 10 | import com.derek_s.hubble_gallery.nav_drawer.views.NavigationView 11 | import java.util.* 12 | 13 | class NavigationPresenter constructor(view: NavigationView, context: Context) : 14 | NavDrawerAdapter.NavAdapterListener { 15 | 16 | final val TAG = "NavigationPresenter" 17 | var view: NavigationView 18 | var context: Context 19 | var mAdapter: NavDrawerAdapter? = null 20 | 21 | val KEY_SELECTED_QUERY = "selected_query" 22 | 23 | init { 24 | this.view = view 25 | this.context = context 26 | } 27 | 28 | fun restoreState(savedState: Bundle?) { 29 | if (savedState == null) 30 | return 31 | 32 | if (savedState.containsKey(KEY_SELECTED_QUERY)) 33 | mAdapter!!.setSelectedQuery(savedState.getString(KEY_SELECTED_QUERY)) 34 | } 35 | 36 | fun getSelectedQuery(): String? { 37 | return mAdapter!!.getSelectedQuery() 38 | } 39 | 40 | fun populateAdapter() { 41 | var drawerItems = ArrayList() 42 | 43 | drawerItems.add(NavigationAdapterItem(SectionChildObject("Entire Collection", "entire"), 44 | NavigationAdapterItem.STANDALONE_SECTION, null)) 45 | 46 | drawerItems.add(NavigationAdapterItem(SectionChildObject("Hubble Heritage", "heritage"), 47 | NavigationAdapterItem.STANDALONE_SECTION, null)) 48 | 49 | /** 50 | * the universe 51 | */ 52 | var universeItems = ArrayList() 53 | universeItems.add(createChildObject("Distant Galaxies", "the_universe/distant_galaxies")) 54 | universeItems.add(createChildObject("GOODS", "the_universe/goods")) 55 | universeItems.add(createChildObject("Hubble Deep Field", "the_universe/hubble_deep_field")) 56 | universeItems.add(createChildObject("Hubble Ultra Deep Field", "the_universe/hubble_ultra_deep_field")) 57 | universeItems.add(createChildObject("Intergalactic Gas", "the_universe/intergalactic_gas")) 58 | universeItems.add(createChildObject("Medium Deep Survey", "the_universe/medium_deep_survey")) 59 | 60 | drawerItems.add(NavigationAdapterItem(SectionChildObject("The Universe", "the_universe"), 61 | NavigationAdapterItem.GROUP, universeItems)) 62 | 63 | /** 64 | * exotic 65 | */ 66 | var exoticItems = ArrayList() 67 | exoticItems.add(createChildObject("Black Hole", "exotic/black_hole")) 68 | exoticItems.add(createChildObject("Dark Matter", "exotic/dark_matter")) 69 | exoticItems.add(createChildObject("Gamma Ray Burst", "exotic/gamma_ray_burst")) 70 | exoticItems.add(createChildObject("Gravitational Lens", "exotic/gravitational_lens")) 71 | 72 | drawerItems.add(NavigationAdapterItem(SectionChildObject("Exotic", "exotic"), 73 | NavigationAdapterItem.GROUP, exoticItems)) 74 | 75 | /** 76 | * galaxies 77 | */ 78 | var galaxyItems = ArrayList() 79 | galaxyItems.add(createChildObject("Cluster", "galaxy/cluster")) 80 | galaxyItems.add(createChildObject("Dwarf", "galaxy/dwarf")) 81 | galaxyItems.add(createChildObject("Elliptical", "galaxy/elliptical")) 82 | galaxyItems.add(createChildObject("Interacting", "galaxy/interacting")) 83 | galaxyItems.add(createChildObject("Irregular", "galaxy/irregular")) 84 | galaxyItems.add(createChildObject("Magellanic Cloud", "galaxy/magellanic_cloud")) 85 | galaxyItems.add(createChildObject("Quasar/Active Nucleus", "galaxy/quasar_active_nucleus")) 86 | 87 | drawerItems.add(NavigationAdapterItem(SectionChildObject("Galaxies", "galaxy"), 88 | NavigationAdapterItem.GROUP, galaxyItems)) 89 | 90 | /** 91 | * nebulae 92 | */ 93 | var nebulaItems = ArrayList() 94 | nebulaItems.add(createChildObject("Dark", "nebula/dark")) 95 | nebulaItems.add(createChildObject("Emission", "nebula/emission")) 96 | nebulaItems.add(createChildObject("Planetary", "nebula/planetary")) 97 | nebulaItems.add(createChildObject("Reflection", "nebula/reflection")) 98 | nebulaItems.add(createChildObject("Supernova Remnant", "nebula/supernova_remnant")) 99 | 100 | drawerItems.add(NavigationAdapterItem(SectionChildObject("Nebulae", "nebula"), 101 | NavigationAdapterItem.GROUP, nebulaItems)) 102 | 103 | /** 104 | * solar system 105 | */ 106 | var solarSystemItems = ArrayList() 107 | solarSystemItems.add(createChildObject("Asteroid", "solar_system/comet")) 108 | solarSystemItems.add(createChildObject("Comet", "solar_system/emission")) 109 | solarSystemItems.add(createChildObject("Jupiter", "solar_system/jupiter")) 110 | solarSystemItems.add(createChildObject("Kuiper Belt Object", "solar_system/kuiper_belt_object")) 111 | solarSystemItems.add(createChildObject("Mars", "solar_system/mars")) 112 | solarSystemItems.add(createChildObject("Neptune", "solar_system/neptune")) 113 | solarSystemItems.add(createChildObject("Planetary Moon", "solar_system/planetary_moon")) 114 | solarSystemItems.add(createChildObject("Planetary Ring", "solar_system/planetary_ring")) 115 | solarSystemItems.add(createChildObject("Pluto", "solar_system/pluto")) 116 | solarSystemItems.add(createChildObject("Saturn", "solar_system/saturn")) 117 | solarSystemItems.add(createChildObject("Uranus", "solar_system/uranus")) 118 | solarSystemItems.add(createChildObject("Venus", "solar_system/venus")) 119 | solarSystemItems.add(createChildObject("Weather/Atmosphere", "solar_system/weather_atmosphere")) 120 | 121 | drawerItems.add(NavigationAdapterItem(SectionChildObject("Solar System", "solar_system"), 122 | NavigationAdapterItem.GROUP, solarSystemItems)) 123 | 124 | /** 125 | * stars 126 | */ 127 | var starItems = ArrayList() 128 | starItems.add(createChildObject("Brown Dwarf", "star/brown_dwarf")) 129 | starItems.add(createChildObject("Massive Star", "star/massive_star")) 130 | starItems.add(createChildObject("Nova", "star/nova")) 131 | starItems.add(createChildObject("Protostellar Jet", "star/protostellar_jet")) 132 | starItems.add(createChildObject("Protoplanetary Disk", "star/protoplanetary_disk")) 133 | starItems.add(createChildObject("Pulsar", "star/pulsar")) 134 | starItems.add(createChildObject("Star Cluster", "star/star_cluster")) 135 | starItems.add(createChildObject("Star Field", "star/star_field")) 136 | starItems.add(createChildObject("Supernova", "star/supernova")) 137 | starItems.add(createChildObject("Variable Star", "star/variable_star")) 138 | starItems.add(createChildObject("White Dwarf", "star/white_dwarf")) 139 | 140 | drawerItems.add(NavigationAdapterItem(SectionChildObject("Stars", "star"), 141 | NavigationAdapterItem.GROUP, starItems)) 142 | 143 | 144 | mAdapter = NavDrawerAdapter(context, drawerItems, this) 145 | 146 | view.recycler.layoutManager = LinearLayoutManager(context) 147 | view.recycler.adapter = mAdapter 148 | } 149 | 150 | private fun createChildObject(title: String, query: String): SectionChildObject { 151 | return SectionChildObject(title, query) 152 | } 153 | 154 | override fun onSectionClicked(section: SectionChildObject) { 155 | view.selectSection(section) 156 | } 157 | 158 | override fun setSelectedQuery(query: String) { 159 | mAdapter!!.setSelectedQuery(query) 160 | } 161 | } 162 | --------------------------------------------------------------------------------