├── .github └── workflows │ └── manual.yml ├── .gitignore ├── CODEOWNERS ├── README.md └── starter ├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── udacity │ │ └── asteroidradar │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── udacity │ │ │ └── asteroidradar │ │ │ ├── Asteroid.kt │ │ │ ├── BindingAdapters.kt │ │ │ ├── Constants.kt │ │ │ ├── MainActivity.kt │ │ │ ├── PictureOfDay.kt │ │ │ ├── api │ │ │ └── NetworkUtils.kt │ │ │ ├── detail │ │ │ └── DetailFragment.kt │ │ │ └── main │ │ │ ├── MainFragment.kt │ │ │ └── MainViewModel.kt │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── asteroid_hazardous.png │ │ ├── asteroid_safe.png │ │ ├── ic_help_circle.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_status_normal.xml │ │ ├── ic_status_potentially_hazardous.xml │ │ └── placeholder_picture_of_day.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── fragment_detail.xml │ │ └── fragment_main.xml │ │ ├── menu │ │ └── main_overflow_menu.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── navigation │ │ └── main_nav_graph.xml │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── udacity │ └── asteroidradar │ └── ExampleUnitTest.kt ├── build.gradle ├── gradle.properties ├── screenshots ├── screen_1.png ├── screen_2.png ├── screen_3.png └── screen_4.png └── settings.gradle /.github/workflows/manual.yml: -------------------------------------------------------------------------------- 1 | # Workflow to ensure whenever a Github PR is submitted, 2 | # a JIRA ticket gets created automatically. 3 | name: Manual Workflow 4 | 5 | # Controls when the action will run. 6 | on: 7 | # Triggers the workflow on pull request events but only for the master branch 8 | pull_request_target: 9 | types: [opened, reopened] 10 | 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | jobs: 15 | test-transition-issue: 16 | name: Convert Github Issue to Jira Issue 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@master 21 | 22 | - name: Login 23 | uses: atlassian/gajira-login@master 24 | env: 25 | JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} 26 | JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} 27 | JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} 28 | 29 | - name: Create NEW JIRA ticket 30 | id: create 31 | uses: atlassian/gajira-create@master 32 | with: 33 | project: CONUPDATE 34 | issuetype: Task 35 | summary: | 36 | Github PR nd940 - Android Kotlin Developer C2 | Repo: ${{ github.repository }} | PR# ${{github.event.number}} 37 | description: | 38 | Repo link: https://github.com/${{ github.repository }} 39 | PR no. ${{ github.event.pull_request.number }} 40 | PR title: ${{ github.event.pull_request.title }} 41 | PR description: ${{ github.event.pull_request.description }} 42 | In addition, please resolve other issues, if any. 43 | fields: '{"components": [{"name":"nd940 - Android Kotlin Developer"}], "customfield_16449":"https://classroom.udacity.com/", "customfield_16450":"Resolve the PR", "labels": ["github"], "priority":{"id": "4"}}' 44 | 45 | - name: Log created issue 46 | run: echo "Issue ${{ steps.create.outputs.issue }} was created" 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches/build_file_checksum.ser 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | .idea 9 | .DS_Store 10 | /build 11 | /captures 12 | .externalNativeBuild 13 | 14 | 15 | # gradle 16 | gradle/ 17 | gradlew* 18 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @udacity/active-public-content -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Project Title 2 | 3 | Asteroid Radar 4 | 5 | ## Getting Started 6 | 7 | Asteroid Radar is an app to view the asteroids detected by NASA that pass near Earth, you can view all the detected asteroids in a period of time, their data (Size, velocity, distance to Earth) and if they are potentially hazardous. 8 | 9 | The app is consists of two screens: A Main screen with a list of all the detected asteroids and a Details screen that is going to display the data of that asteroid once it´s selected in the Main screen list. The main screen will also show the NASA image of the day to make the app more striking. 10 | 11 | This kind of app is one of the most usual in the real world, what you will learn by doing this are some of the most fundamental skills you need to know to work as a professional Android developer, as fetching data from the internet, saving data to a database, and display the data in a clear, clear, compelling UI. 12 | 13 | ## Requirements 14 | 15 | 1. Android Studio (Jellyfish or above) 16 | 2. JDK 21 with `JAVA_HOME` environment variable set. If you don't have JDK 21 installed or `JAVA_HOME` is not set, consider using a tool like `sdkman` to simplify the process. Refer to the sdkman documentation for installation instructions: [sdkman installation](https://sdkman.io/install) 17 | 18 | ### Screenshots 19 | 20 | ![Screenshot 1](starter/screenshots/screen_1.png) 21 | ![Screenshot 2](starter/screenshots/screen_2.png) 22 | ![Screenshot 3](starter/screenshots/screen_3.png) 23 | ![Screenshot 4](starter/screenshots/screen_4.png) 24 | 25 | ### Installation 26 | 27 | To get the project running on your local machine, you need to follow these steps: 28 | 29 | **Step 1: Clone the repo** 30 | 31 | Use this to clone it to your local machine: 32 | ```bash 33 | git clone https://github.com/udacity/REPOSITORY_NAME.git 34 | ``` 35 | 36 | **Step 2: Check out the ‘master’ branch** 37 | 38 | This branch is going to let you start working with it. The command to check out a branch would be: 39 | 40 | ```bash 41 | git checkout master 42 | ``` 43 | 44 | **Step 3: Run the project and check that it compiles correctly** 45 | 46 | Open the project in Android Studio and click the Run ‘app’ button, check that it runs correctly and you can see the app in your device or emulator. 47 | 48 | ## Testing 49 | 50 | Explain the steps needed to run any automated tests 51 | 52 | ### Break Down Tests 53 | 54 | Explain what each test does and why 55 | 56 | ``` 57 | Examples here 58 | ``` 59 | ## Project Instructions 60 | 61 | You will be provided with a starter code, which includes the necessary dependencies and plugins that you have been using along the courses and that you are going to need to complete this project. 62 | 63 | The most important dependencies we are using are: 64 | - Retrofit to download the data from the Internet. 65 | - Moshi to convert the JSON data we are downloading to usable data in form of custom classes. 66 | - Glide to download and cache images. 67 | - RecyclerView to display the asteroids in a list. 68 | 69 | We recommend you following the guidelines seen in the courses, as well as using the components from the Jetpack library: 70 | - ViewModel 71 | - Room 72 | - LiveData 73 | - Data Binding 74 | - Navigation 75 | 76 | Android Studio could display a message to update Gradle plugin, or another thing like Kotlin, although it is recommended to have the last versions, it could be you have to do other things in order to make it work. 77 | 78 | The application you will build must: 79 | - Include Main screen with a list of clickable asteroids as seen in the provided design. 80 | - Include a Details screen that displays the selected asteroid data once it’s clicked in the Main screen as seen in the provided design. The images in the details screen are going to be provided here, an image for a potentially hazardous asteroids and another one for the non potentially hazardous ones. 81 | - Download and parse data from the NASA NeoWS (Near Earth Object Web Service) API. 82 | - Save the selected asteroid data in the database using a button in details screen. 83 | - Once you save an asteroid in the database, you should be able to display the list of asteroids from web or the database in the main screen top menu. 84 | - Be able to cache the asteroids data by using a worker, so it downloads and saves week asteroids in background when device is charging and wifi is enabled. 85 | - App works in multiple screen sizes and orientations, also it provides talk back and push button navigation. 86 | 87 | 88 | ## Built With 89 | 90 | To build this project you are going to use the NASA NeoWS (Near Earth Object Web Service) API, which you can find here. 91 | https://api.nasa.gov/ 92 | 93 | You will need an API Key which is provided for you in that same link, just fill the fields in the form and click Signup. 94 | 95 | ## License 96 | 97 | 98 | -------------------------------------------------------------------------------- /starter/.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.aar 4 | *.ap_ 5 | *.aab 6 | 7 | # Files for the ART/Dalvik VM 8 | *.dex 9 | 10 | # Java class files 11 | *.class 12 | 13 | # Generated files 14 | bin/ 15 | gen/ 16 | out/ 17 | # Uncomment the following line in case you need and you don't have the release build type files in your app 18 | # release/ 19 | 20 | # Gradle files 21 | .gradle/ 22 | build/ 23 | 24 | # Local configuration file (sdk path, etc) 25 | local.properties 26 | 27 | # Proguard folder generated by Eclipse 28 | proguard/ 29 | 30 | # Log Files 31 | *.log 32 | 33 | # Android Studio Navigation editor temp files 34 | .navigation/ 35 | 36 | # Android Studio captures folder 37 | captures/ 38 | 39 | # IntelliJ 40 | *.iml 41 | .idea/workspace.xml 42 | .idea/tasks.xml 43 | .idea/gradle.xml 44 | .idea/assetWizardSettings.xml 45 | .idea/dictionaries 46 | .idea/libraries 47 | # Android Studio 3 in .gitignore file. 48 | .idea/caches 49 | .idea/modules.xml 50 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you 51 | .idea/navEditor.xml 52 | 53 | # Keystore files 54 | # Uncomment the following lines if you do not want to check your keystore files in. 55 | #*.jks 56 | #*.keystore 57 | 58 | # External native build folder generated in Android Studio 2.2 and later 59 | .externalNativeBuild 60 | .cxx/ 61 | 62 | # Google Services (e.g. APIs or Firebase) 63 | # google-services.json 64 | 65 | # Freeline 66 | freeline.py 67 | freeline/ 68 | freeline_project_description.json 69 | 70 | # fastlane 71 | fastlane/report.xml 72 | fastlane/Preview.html 73 | fastlane/screenshots 74 | fastlane/test_output 75 | fastlane/readme.md 76 | 77 | # Version control 78 | vcs.xml 79 | 80 | # lint 81 | lint/intermediates/ 82 | lint/generated/ 83 | lint/outputs/ 84 | lint/tmp/ 85 | # lint/reports/ 86 | -------------------------------------------------------------------------------- /starter/README.md: -------------------------------------------------------------------------------- 1 | # Purpose of this Folder 2 | 3 | This folder should contain the scaffolded project files to get a student started on their project. This repo will be added to the Classroom for students to use, so please do not have any solutions in this folder. 4 | 5 | ## Note: Android Kotlin Gradle Update 6 | Use the updated Gradle version in the `~/gradle/wrapper/gradle-wrapper.properties` file: 7 | ``` 8 | distributionUrl = https\://services.gradle.org/distributions/gradle-8.8-all.zip 9 | ``` 10 | -------------------------------------------------------------------------------- /starter/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /starter/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'kotlin-android' 4 | id 'kotlin-kapt' 5 | id 'androidx.navigation.safeargs' 6 | id 'kotlin-parcelize' 7 | } 8 | 9 | android { 10 | namespace 'com.udacity.asteroidradar' 11 | compileSdk 34 12 | 13 | defaultConfig { 14 | applicationId "com.udacity.asteroidradar" 15 | minSdkVersion 24 16 | targetSdkVersion 34 17 | versionCode 1 18 | versionName "1.0" 19 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 20 | } 21 | buildTypes { 22 | release { 23 | minifyEnabled false 24 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 25 | } 26 | } 27 | buildFeatures { 28 | dataBinding true 29 | } 30 | compileOptions { 31 | sourceCompatibility = JavaVersion.VERSION_21 32 | targetCompatibility = JavaVersion.VERSION_21 33 | } 34 | } 35 | 36 | dependencies { 37 | // Design 38 | implementation "androidx.appcompat:appcompat:$version_appcompat" 39 | implementation "androidx.constraintlayout:constraintlayout:$version_constraint_layout" 40 | 41 | // Core with Ktx 42 | implementation "androidx.core:core-ktx:$version_core" 43 | 44 | // ViewModel and LiveData 45 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$version_lifecycle" 46 | 47 | // Retrofit with Moshi Converter 48 | implementation "com.squareup.retrofit2:retrofit:$version_retrofit" 49 | implementation "com.squareup.retrofit2:converter-moshi:$version_retrofit" 50 | implementation "com.squareup.retrofit2:converter-scalars:$version_retrofit" 51 | 52 | // Moshi 53 | implementation "com.squareup.moshi:moshi:$version_moshi" 54 | implementation "com.squareup.moshi:moshi-kotlin:$version_moshi" 55 | 56 | // Navigation 57 | implementation "androidx.navigation:navigation-fragment-ktx:$version_navigation" 58 | implementation "androidx.navigation:navigation-ui-ktx:$version_navigation" 59 | 60 | // Room database 61 | implementation "androidx.room:room-runtime:$version_room" 62 | kapt "androidx.room:room-compiler:$version_room" 63 | // Kotlin Extensions and Coroutines support for Room 64 | implementation "androidx.room:room-ktx:$version_room" 65 | 66 | // Glide 67 | implementation "com.github.bumptech.glide:glide:$version_glide" 68 | annotationProcessor "com.github.bumptech.glide:compiler:$version_glide" 69 | implementation 'com.squareup.picasso:picasso:2.5.2' 70 | 71 | // WorkManager 72 | implementation "androidx.work:work-runtime-ktx:$version_work" 73 | 74 | // Tests 75 | testImplementation 'junit:junit:4.13.2' 76 | androidTestImplementation 'androidx.test.ext:junit:1.1.5' 77 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' 78 | } 79 | -------------------------------------------------------------------------------- /starter/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /starter/app/src/androidTest/java/com/udacity/asteroidradar/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.udacity.asteroidradar 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.udacity.asteroidradar", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /starter/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /starter/app/src/main/java/com/udacity/asteroidradar/Asteroid.kt: -------------------------------------------------------------------------------- 1 | package com.udacity.asteroidradar 2 | 3 | import android.os.Parcelable 4 | import kotlinx.android.parcel.Parcelize 5 | 6 | @Parcelize 7 | data class Asteroid(val id: Long, val codename: String, val closeApproachDate: String, 8 | val absoluteMagnitude: Double, val estimatedDiameter: Double, 9 | val relativeVelocity: Double, val distanceFromEarth: Double, 10 | val isPotentiallyHazardous: Boolean) : Parcelable -------------------------------------------------------------------------------- /starter/app/src/main/java/com/udacity/asteroidradar/BindingAdapters.kt: -------------------------------------------------------------------------------- 1 | package com.udacity.asteroidradar 2 | 3 | import android.widget.ImageView 4 | import android.widget.TextView 5 | import androidx.databinding.BindingAdapter 6 | 7 | @BindingAdapter("statusIcon") 8 | fun bindAsteroidStatusImage(imageView: ImageView, isHazardous: Boolean) { 9 | if (isHazardous) { 10 | imageView.setImageResource(R.drawable.ic_status_potentially_hazardous) 11 | } else { 12 | imageView.setImageResource(R.drawable.ic_status_normal) 13 | } 14 | } 15 | 16 | @BindingAdapter("asteroidStatusImage") 17 | fun bindDetailsStatusImage(imageView: ImageView, isHazardous: Boolean) { 18 | if (isHazardous) { 19 | imageView.setImageResource(R.drawable.asteroid_hazardous) 20 | } else { 21 | imageView.setImageResource(R.drawable.asteroid_safe) 22 | } 23 | } 24 | 25 | @BindingAdapter("astronomicalUnitText") 26 | fun bindTextViewToAstronomicalUnit(textView: TextView, number: Double) { 27 | val context = textView.context 28 | textView.text = String.format(context.getString(R.string.astronomical_unit_format), number) 29 | } 30 | 31 | @BindingAdapter("kmUnitText") 32 | fun bindTextViewToKmUnit(textView: TextView, number: Double) { 33 | val context = textView.context 34 | textView.text = String.format(context.getString(R.string.km_unit_format), number) 35 | } 36 | 37 | @BindingAdapter("velocityText") 38 | fun bindTextViewToDisplayVelocity(textView: TextView, number: Double) { 39 | val context = textView.context 40 | textView.text = String.format(context.getString(R.string.km_s_unit_format), number) 41 | } 42 | -------------------------------------------------------------------------------- /starter/app/src/main/java/com/udacity/asteroidradar/Constants.kt: -------------------------------------------------------------------------------- 1 | package com.udacity.asteroidradar 2 | 3 | object Constants { 4 | const val API_QUERY_DATE_FORMAT = "YYYY-MM-dd" 5 | const val DEFAULT_END_DATE_DAYS = 7 6 | const val BASE_URL = "https://api.nasa.gov/" 7 | } -------------------------------------------------------------------------------- /starter/app/src/main/java/com/udacity/asteroidradar/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.udacity.asteroidradar 2 | 3 | import android.os.Bundle 4 | import androidx.appcompat.app.AppCompatActivity 5 | 6 | class MainActivity : AppCompatActivity() { 7 | 8 | override fun onCreate(savedInstanceState: Bundle?) { 9 | super.onCreate(savedInstanceState) 10 | setContentView(R.layout.activity_main) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /starter/app/src/main/java/com/udacity/asteroidradar/PictureOfDay.kt: -------------------------------------------------------------------------------- 1 | package com.udacity.asteroidradar 2 | 3 | import com.squareup.moshi.Json 4 | 5 | data class PictureOfDay(@Json(name = "media_type") val mediaType: String, val title: String, 6 | val url: String) -------------------------------------------------------------------------------- /starter/app/src/main/java/com/udacity/asteroidradar/api/NetworkUtils.kt: -------------------------------------------------------------------------------- 1 | package com.udacity.asteroidradar.api 2 | 3 | import com.udacity.asteroidradar.Asteroid 4 | import com.udacity.asteroidradar.Constants 5 | import org.json.JSONObject 6 | import java.text.SimpleDateFormat 7 | import java.util.* 8 | import kotlin.collections.ArrayList 9 | 10 | fun parseAsteroidsJsonResult(jsonResult: JSONObject): ArrayList { 11 | val nearEarthObjectsJson = jsonResult.getJSONObject("near_earth_objects") 12 | 13 | val asteroidList = ArrayList() 14 | 15 | val nextSevenDaysFormattedDates = getNextSevenDaysFormattedDates() 16 | for (formattedDate in nextSevenDaysFormattedDates) { 17 | if (nearEarthObjectsJson.has(formattedDate)) { 18 | val dateAsteroidJsonArray = nearEarthObjectsJson.getJSONArray(formattedDate) 19 | 20 | for (i in 0 until dateAsteroidJsonArray.length()) { 21 | val asteroidJson = dateAsteroidJsonArray.getJSONObject(i) 22 | val id = asteroidJson.getLong("id") 23 | val codename = asteroidJson.getString("name") 24 | val absoluteMagnitude = asteroidJson.getDouble("absolute_magnitude_h") 25 | val estimatedDiameter = asteroidJson.getJSONObject("estimated_diameter") 26 | .getJSONObject("kilometers").getDouble("estimated_diameter_max") 27 | 28 | val closeApproachData = asteroidJson 29 | .getJSONArray("close_approach_data").getJSONObject(0) 30 | val relativeVelocity = closeApproachData.getJSONObject("relative_velocity") 31 | .getDouble("kilometers_per_second") 32 | val distanceFromEarth = closeApproachData.getJSONObject("miss_distance") 33 | .getDouble("astronomical") 34 | val isPotentiallyHazardous = asteroidJson 35 | .getBoolean("is_potentially_hazardous_asteroid") 36 | 37 | val asteroid = Asteroid(id, codename, formattedDate, absoluteMagnitude, 38 | estimatedDiameter, relativeVelocity, distanceFromEarth, isPotentiallyHazardous) 39 | asteroidList.add(asteroid) 40 | } 41 | } 42 | } 43 | 44 | return asteroidList 45 | } 46 | 47 | private fun getNextSevenDaysFormattedDates(): ArrayList { 48 | val formattedDateList = ArrayList() 49 | 50 | val calendar = Calendar.getInstance() 51 | for (i in 0..Constants.DEFAULT_END_DATE_DAYS) { 52 | val currentTime = calendar.time 53 | val dateFormat = SimpleDateFormat(Constants.API_QUERY_DATE_FORMAT, Locale.getDefault()) 54 | formattedDateList.add(dateFormat.format(currentTime)) 55 | calendar.add(Calendar.DAY_OF_YEAR, 1) 56 | } 57 | 58 | return formattedDateList 59 | } 60 | -------------------------------------------------------------------------------- /starter/app/src/main/java/com/udacity/asteroidradar/detail/DetailFragment.kt: -------------------------------------------------------------------------------- 1 | package com.udacity.asteroidradar.detail 2 | 3 | 4 | import android.os.Bundle 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import androidx.appcompat.app.AlertDialog 9 | import androidx.fragment.app.Fragment 10 | import com.udacity.asteroidradar.R 11 | import com.udacity.asteroidradar.databinding.FragmentDetailBinding 12 | 13 | class DetailFragment : Fragment() { 14 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, 15 | savedInstanceState: Bundle?): View? { 16 | val binding = FragmentDetailBinding.inflate(inflater) 17 | binding.lifecycleOwner = this 18 | 19 | val asteroid = DetailFragmentArgs.fromBundle(arguments!!).selectedAsteroid 20 | 21 | binding.asteroid = asteroid 22 | 23 | binding.helpButton.setOnClickListener { 24 | displayAstronomicalUnitExplanationDialog() 25 | } 26 | 27 | return binding.root 28 | } 29 | 30 | private fun displayAstronomicalUnitExplanationDialog() { 31 | val builder = AlertDialog.Builder(activity!!) 32 | .setMessage(getString(R.string.astronomica_unit_explanation)) 33 | .setPositiveButton(android.R.string.ok, null) 34 | builder.create().show() 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /starter/app/src/main/java/com/udacity/asteroidradar/main/MainFragment.kt: -------------------------------------------------------------------------------- 1 | package com.udacity.asteroidradar.main 2 | 3 | import android.os.Bundle 4 | import android.view.* 5 | import androidx.fragment.app.Fragment 6 | import androidx.lifecycle.ViewModelProvider 7 | import com.udacity.asteroidradar.R 8 | import com.udacity.asteroidradar.databinding.FragmentMainBinding 9 | 10 | class MainFragment : Fragment() { 11 | 12 | private val viewModel: MainViewModel by lazy { 13 | ViewModelProvider(this).get(MainViewModel::class.java) 14 | } 15 | 16 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, 17 | savedInstanceState: Bundle?): View? { 18 | val binding = FragmentMainBinding.inflate(inflater) 19 | binding.lifecycleOwner = this 20 | 21 | binding.viewModel = viewModel 22 | 23 | setHasOptionsMenu(true) 24 | 25 | return binding.root 26 | } 27 | 28 | override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { 29 | inflater.inflate(R.menu.main_overflow_menu, menu) 30 | super.onCreateOptionsMenu(menu, inflater) 31 | } 32 | 33 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 34 | return true 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /starter/app/src/main/java/com/udacity/asteroidradar/main/MainViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.udacity.asteroidradar.main 2 | 3 | import androidx.lifecycle.ViewModel 4 | 5 | class MainViewModel : ViewModel() { 6 | } -------------------------------------------------------------------------------- /starter/app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /starter/app/src/main/res/drawable/asteroid_hazardous.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd940-android-kotlin-c2-starter/6034fb6335c241b13d967bbe0cdc057d5d9bdcc6/starter/app/src/main/res/drawable/asteroid_hazardous.png -------------------------------------------------------------------------------- /starter/app/src/main/res/drawable/asteroid_safe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd940-android-kotlin-c2-starter/6034fb6335c241b13d967bbe0cdc057d5d9bdcc6/starter/app/src/main/res/drawable/asteroid_safe.png -------------------------------------------------------------------------------- /starter/app/src/main/res/drawable/ic_help_circle.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /starter/app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /starter/app/src/main/res/drawable/ic_status_normal.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /starter/app/src/main/res/drawable/ic_status_potentially_hazardous.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /starter/app/src/main/res/drawable/placeholder_picture_of_day.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /starter/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /starter/app/src/main/res/layout/fragment_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 17 | 18 | 28 | 29 | 36 | 37 | 41 | 42 | 46 | 47 | 52 | 53 | 61 | 62 | 63 | 69 | 70 | 75 | 76 | 81 | 82 | 90 | 91 | 92 | 98 | 99 | 100 | 101 | 107 | 108 | 116 | 117 | 123 | 124 | 132 | 133 | 139 | 140 | 148 | 149 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /starter/app/src/main/res/layout/fragment_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 16 | 17 | 24 | 25 | 32 | 33 | 44 | 45 | 46 | 57 | 58 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /starter/app/src/main/res/menu/main_overflow_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /starter/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /starter/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /starter/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd940-android-kotlin-c2-starter/6034fb6335c241b13d967bbe0cdc057d5d9bdcc6/starter/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /starter/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd940-android-kotlin-c2-starter/6034fb6335c241b13d967bbe0cdc057d5d9bdcc6/starter/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /starter/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd940-android-kotlin-c2-starter/6034fb6335c241b13d967bbe0cdc057d5d9bdcc6/starter/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /starter/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd940-android-kotlin-c2-starter/6034fb6335c241b13d967bbe0cdc057d5d9bdcc6/starter/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /starter/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd940-android-kotlin-c2-starter/6034fb6335c241b13d967bbe0cdc057d5d9bdcc6/starter/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /starter/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd940-android-kotlin-c2-starter/6034fb6335c241b13d967bbe0cdc057d5d9bdcc6/starter/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /starter/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd940-android-kotlin-c2-starter/6034fb6335c241b13d967bbe0cdc057d5d9bdcc6/starter/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /starter/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd940-android-kotlin-c2-starter/6034fb6335c241b13d967bbe0cdc057d5d9bdcc6/starter/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /starter/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd940-android-kotlin-c2-starter/6034fb6335c241b13d967bbe0cdc057d5d9bdcc6/starter/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /starter/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd940-android-kotlin-c2-starter/6034fb6335c241b13d967bbe0cdc057d5d9bdcc6/starter/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /starter/app/src/main/res/navigation/main_nav_graph.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 15 | 16 | 17 | 22 | 23 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /starter/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #010613 4 | #010613 5 | #FF8282 6 | #010613 7 | #FFFFFF 8 | #D2D2D2 9 | #FF8282 10 | 11 | -------------------------------------------------------------------------------- /starter/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Asteroid Radar 3 | 4 | View week asteroids 5 | View today asteroids 6 | View saved asteroids 7 | Close approach date 8 | Absolute magnitude 9 | Estimated diameter 10 | Relative velocity 11 | Distance from earth 12 | %f au 13 | %f km 14 | %f km/s 15 | Image of the Day 16 | The astronomical unit (au) is a unit of length, roughly the distance from Earth to the Sun and equal to about 150 million kilometres (93 million miles) 17 | Astronomical unit definition 18 | Potentially hazardous asteroid image 19 | Not hazardous asteroid image 20 | This is NASA\'s picture of day, showing nothing yet 21 | NASA\'s picture of day: %s 22 | 23 | -------------------------------------------------------------------------------- /starter/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /starter/app/src/test/java/com/udacity/asteroidradar/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.udacity.asteroidradar 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /starter/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | buildscript { 3 | ext { 4 | version_core = "1.13.1" 5 | version_constraint_layout = "2.1.4" 6 | version_gradle = '8.4.2' 7 | version_kotlin = "1.9.24" 8 | version_lifecycle = "2.8.2" 9 | version_navigation = '2.7.7' 10 | version_glide = "4.16.0" 11 | version_moshi = "1.15.1" 12 | version_retrofit = "2.9.0" 13 | version_recyclerview = "1.3.2" 14 | version_work = "2.9.0" 15 | version_room = "2.6.1" 16 | version_appcompat = "1.7.0" 17 | } 18 | 19 | repositories { 20 | mavenCentral() 21 | google() 22 | } 23 | dependencies { 24 | classpath "com.android.tools.build:gradle:$version_gradle" 25 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$version_kotlin" 26 | classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$version_navigation" 27 | 28 | // NOTE: Do not place your application dependencies here; they belong 29 | // in the individual module build.gradle files 30 | } 31 | } -------------------------------------------------------------------------------- /starter/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | -------------------------------------------------------------------------------- /starter/screenshots/screen_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd940-android-kotlin-c2-starter/6034fb6335c241b13d967bbe0cdc057d5d9bdcc6/starter/screenshots/screen_1.png -------------------------------------------------------------------------------- /starter/screenshots/screen_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd940-android-kotlin-c2-starter/6034fb6335c241b13d967bbe0cdc057d5d9bdcc6/starter/screenshots/screen_2.png -------------------------------------------------------------------------------- /starter/screenshots/screen_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd940-android-kotlin-c2-starter/6034fb6335c241b13d967bbe0cdc057d5d9bdcc6/starter/screenshots/screen_3.png -------------------------------------------------------------------------------- /starter/screenshots/screen_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/nd940-android-kotlin-c2-starter/6034fb6335c241b13d967bbe0cdc057d5d9bdcc6/starter/screenshots/screen_4.png -------------------------------------------------------------------------------- /starter/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | google() 5 | mavenCentral() 6 | } 7 | } 8 | dependencyResolutionManagement { 9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 10 | repositories { 11 | google() 12 | mavenCentral() 13 | } 14 | } 15 | rootProject.name='Asteroid Radar' 16 | include ':app' 17 | --------------------------------------------------------------------------------