9 |
10 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Code of Conduct
2 |
3 | This code of conduct outlines our expectations for participants within the [@TheCodeMonks](https://github.com/TheCodeMonks) community, as well as steps to reporting unacceptable behavior. We are committed to providing a welcoming and inspiring community for all and expect our code of conduct to be honored. Anyone who violates this code of conduct may be banned from the community.
4 |
5 | Our open source community strives to:
6 |
7 | * **Be friendly and patient.**
8 | * **Be welcoming**: We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, colour, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability.
9 |
10 | * **Be considerate**: Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary language.
11 |
12 | * **Be respectful**: Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It’s important to remember that a community where people feel uncomfortable or threatened is not a productive one.
13 |
14 | * **Be careful in the words that you choose**: we are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behavior aren't acceptable. This includes, but is not limited to:
15 | * Violent threats or language directed against another person.
16 | * Discriminatory jokes and language.
17 | * Posting sexually explicit or violent material.
18 | * Posting (or threatening to post) other people's personally identifying information ("doxing").
19 | * Personal insults, especially those using racist or sexist terms.
20 | * Unwelcome sexual attention.
21 | * Advocating for, or encouraging, any of the above behavior.
22 | * Repeated harassment of others. In general, if someone asks you to stop, then stop.
23 |
24 | * **When we disagree, try to understand why**: Disagreements, both social and technical, happen all the time. It is important that we resolve disagreements and differing views constructively. Remember that we’re different. The strength of our community comes from its diversity, people from a wide range of backgrounds. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesn’t mean that they’re wrong. Don’t forget that it is human to err and blaming each other doesn’t get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes.
25 |
26 | This code is not exhaustive or complete. It serves to distill our common understanding of a collaborative, shared environment, and goals. We expect it to be followed in spirit as much as in the letter.
27 |
28 | ### Diversity Statement
29 |
30 | We encourage everyone to participate and are committed to building a community for all. Although we may not be able to satisfy everyone, we all agree that everyone is equal. Whenever a participant has made a mistake, we expect them to take responsibility for it. If someone has been harmed or offended, it is our responsibility to listen carefully and respectfully, and do our best to right the wrong.
31 |
32 | Although this list cannot be exhaustive, we explicitly honor diversity in age, gender, gender identity or expression, culture, ethnicity, language, national origin, political beliefs, profession, race, religion, sexual orientation, socioeconomic status, and technical ability. We will not tolerate discrimination based on any of the protected
33 | characteristics above, including participants with disabilities.
34 |
35 | ### Reporting Issues
36 |
37 | If you experience or witness unacceptable behavior—or have any other concerns—please report it by contacting us via [thecodemonksorg@gmail.com](mailto:thecodemonksorg@gmail.com). All reports will be handled with discretion. In your report please include:
38 |
39 | - Your contact information.
40 | - Names (real, nicknames, or pseudonyms) of any individuals involved. If there are additional witnesses, please
41 | include them as well. Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly available record (e.g. a mailing list archive or a public IRC logger), please include a link.
42 | - Any additional information that may be helpful.
43 |
44 | After filing a report, a representative will contact you personally. If the person who is harassing you is part of the response team, they will recuse themselves from handling your incident. A representative will then review the incident, follow up with any additional questions, and make a decision as to how to respond. We will respect confidentiality requests for the purpose of protecting victims of abuse.
45 |
46 | Anyone asked to stop unacceptable behavior is expected to comply immediately. If an individual engages in unacceptable behavior, the representative may take any action they deem appropriate, up to and including a permanent ban from our community without warning.
47 |
48 | ## Thanks
49 |
50 | This code of conduct is based on the [Open Code of Conduct](https://github.com/todogroup/opencodeofconduct) from the [TODOGroup](http://todogroup.org).
51 |
52 | We are thankful for their work and all the communities who have paved the way with code of conducts.
53 |
--------------------------------------------------------------------------------
/CONTRIBUTION.md:
--------------------------------------------------------------------------------
1 | ## Welcome Monk!, Thanks for making our community great.
2 |
3 | ### What you can do
4 | You can contribute us by filing issues, bugs and PRs.
5 |
6 | ### Contributing guidelines:
7 | - Open issue regarding proposed change.
8 | - Repo owner will contact you there.
9 | - If your proposed change is approved, Fork this repo and do changes.
10 | - Open PR against latest `dev` branch. Add nice description in PR.
11 | - You're done!
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 The Code Monks
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | 
4 |
5 | # 🗞 NY Times
6 | **NY Times** is an Minimal News 🗞 Android application built to describe the use of JSoup with Modern Android development tools. *Made with love ❤️ by [Spikeysanju](https://github.com/Spikeysanju)*
7 |
8 | ***Try latest NY Times app apk from below 👇***
9 |
10 | [](https://github.com/TheCodeMonks/NYTimes-App/releases/download/v1.4.3/nytimes.apk)
11 |
12 |
13 | ## Built With 🛠
14 | - [Kotlin](https://kotlinlang.org/) - First class and official programming language for Android development.
15 | - [JSoup](https://jsoup.org/) - Open source Java HTML parser, with the best of HTML5 DOM methods and CSS selectors, for easy data extraction.
16 | - [Coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html) - For asynchronous and more..
17 | - [Android Architecture Components](https://developer.android.com/topic/libraries/architecture) - Collection of libraries that help you design robust, testable, and maintainable apps.
18 | - [Flow](https://kotlinlang.org/docs/reference/coroutines/flow.html) - A flow is an asynchronous version of a Sequence, a type of collection whose values are lazily produced.
19 | - [Jetpack DataStore](https://developer.android.com/topic/libraries/architecture/datastore) - Jetpack DataStore is a data storage solution that allows you to store key-value pairs or typed objects with protocol buffers. DataStore uses Kotlin coroutines and Flow to store data asynchronously, consistently, and transactionally
20 | - [LiveData](https://developer.android.com/topic/libraries/architecture/livedata) - Data objects that notify views when the underlying database changes.
21 | - [ViewModel](https://developer.android.com/topic/libraries/architecture/viewmodel) - Stores UI-related data that isn't destroyed on UI changes.
22 | - [Room](https://developer.android.com/topic/libraries/architecture/room) - SQLite object mapping library.
23 | - [Jetpack Navigation](https://developer.android.com/guide/navigation) - Navigation refers to the interactions that allow users to navigate across, into, and back out from the different pieces of content within your app
24 | - [Material Components for Android](https://github.com/material-components/material-components-android) - Modular and customizable Material Design UI components for Android.
25 |
26 |
27 | # Package Structure
28 |
29 | www.thecodemonks.techbytes # Root Package
30 | .
31 | ├── data # For data handling.
32 | │ ├── db # Local Persistence Database. Room (SQLite) database
33 | | │ ├── dao # Data Access Object for Room
34 | | | |── database # Datbase Instance
35 | |
36 | ├── model # Model classes
37 | |
38 | |
39 | ├── ui # Activity/View layer
40 | │ ├── |── base # Base Activity
41 | | │ ├── adapter # Adapter for RecyclerView
42 | | │ └── viewmodel # Viewmodels for Articles
43 | | │ ├── articles # Articles Fragment
44 | | │ ├── details # Details Fragment
45 | | │ ├── bookmarks # Bookmarks Fragment
46 | |
47 | |
48 | |── utils # Utils for URls
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | ## Architecture
57 |
58 | This app uses [***MVVM (Model View View-Model)***](https://developer.android.com/jetpack/docs/guide#recommended-app-arch) architecture.
59 |
60 | 
61 |
62 |
63 | ## Contribute
64 | If you want to contribute to this library, you're always welcome!
65 | See [Contributing Guidelines](https://github.com/TheCodeMonks/Notzz-App/blob/master/CONTRIBUTION.md).
66 |
67 | ## Contact
68 | Have an project? DM us at 👇
69 |
70 | Drop a mail to:- thecodemonksorg@gmail.com
71 |
72 | # Donation
73 | If this project help you reduce time to develop, you can give me a cup of coffee :)
74 |
75 | [](https://www.paypal.com/paypalme2/spikeysanju)
76 |
77 |
78 | ## License
79 | ```
80 | MIT License
81 |
82 | Copyright (c) 2020 TheCodeMonks
83 |
84 | Permission is hereby granted, free of charge, to any person obtaining a copy
85 | of this software and associated documentation files (the "Software"), to deal
86 | in the Software without restriction, including without limitation the rights
87 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
88 | copies of the Software, and to permit persons to whom the Software is
89 | furnished to do so, subject to the following conditions:
90 |
91 | The above copyright notice and this permission notice shall be included in all
92 | copies or substantial portions of the Software.
93 |
94 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
95 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
96 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
97 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
98 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
99 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
100 | SOFTWARE.
101 | ```
102 |
--------------------------------------------------------------------------------
/apk/nytimes.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeMonks/NYTimes-App/f74e3820d68e29f9ac7feecb5fdf58725272480f/apk/nytimes.apk
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | plugins {
28 | id 'com.android.application'
29 | id 'kotlin-android'
30 | id 'kotlin-kapt'
31 | id 'androidx.navigation.safeargs.kotlin'
32 | id 'dagger.hilt.android.plugin'
33 | }
34 |
35 |
36 | android {
37 | compileSdkVersion 30
38 |
39 | defaultConfig {
40 | applicationId "www.thecodemonks.techbytes"
41 | minSdkVersion 21
42 | targetSdkVersion 30
43 | versionCode 1
44 | versionName "1.1.1"
45 |
46 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
47 | javaCompileOptions {
48 | annotationProcessorOptions {
49 | arguments += [
50 | "room.schemaLocation" : "$projectDir/schemas".toString(),
51 | "room.incremental" : "true",
52 | "room.expandProjection": "true"]
53 | }
54 | }
55 | }
56 |
57 | buildFeatures {
58 | viewBinding true
59 | }
60 |
61 | buildTypes {
62 | release {
63 | minifyEnabled false
64 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
65 | }
66 | }
67 |
68 | compileOptions {
69 | sourceCompatibility JavaVersion.VERSION_1_8
70 | targetCompatibility JavaVersion.VERSION_1_8
71 | }
72 |
73 | kotlinOptions {
74 | jvmTarget = JavaVersion.VERSION_1_8.toString()
75 | }
76 | }
77 |
78 | dependencies {
79 |
80 | implementation 'androidx.work:work-runtime:2.5.0'
81 | def work_version = "2.5.0"
82 |
83 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
84 | implementation 'androidx.core:core-ktx:1.3.2'
85 | implementation 'androidx.appcompat:appcompat:1.2.0'
86 | implementation 'com.google.android.material:material:1.3.0'
87 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
88 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
89 | testImplementation 'junit:junit:4.13.2'
90 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
91 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
92 |
93 | // Architectural Components
94 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0"
95 |
96 | // Room
97 | implementation "androidx.room:room-runtime:2.2.6"
98 | kapt "androidx.room:room-compiler:2.2.6"
99 |
100 | // Kotlin Extensions and Coroutines support for Room
101 | implementation "androidx.room:room-ktx:2.2.6"
102 |
103 | // LiveData
104 | implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.0"
105 |
106 | // Coroutines
107 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2'
108 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2'
109 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.4.1'
110 |
111 | // Navigation Components
112 | implementation "androidx.navigation:navigation-fragment-ktx:2.3.3"
113 | implementation "androidx.navigation:navigation-ui-ktx:2.3.3"
114 |
115 | // Coroutine Lifecycle Scopes
116 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0"
117 | implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.3.0"
118 |
119 | // Coil-kt
120 | implementation 'io.coil-kt:coil:1.1.0'
121 |
122 | // JSoup for HTML parsing
123 | implementation 'org.jsoup:jsoup:1.13.1'
124 |
125 | // Kotlin + coroutines
126 | implementation "androidx.work:work-runtime-ktx:$work_version"
127 |
128 | // Preferences DataStore
129 | implementation "androidx.datastore:datastore-preferences:1.0.0-alpha06"
130 |
131 | // Hilt dependency injection
132 | implementation "com.google.dagger:hilt-android:$hilt_version"
133 | kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
134 |
135 | // Hilt support for lifecycle + viewModels + workManager
136 | implementation "androidx.hilt:hilt-lifecycle-viewmodel:$hilt_support"
137 | implementation "androidx.hilt:hilt-work:$hilt_support"
138 | kapt "androidx.hilt:hilt-compiler:$hilt_support"
139 | }
140 |
--------------------------------------------------------------------------------
/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
--------------------------------------------------------------------------------
/app/src/androidTest/java/www/thecodemonks/techbytes/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package www.thecodemonks.techbytes
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import androidx.test.platform.app.InstrumentationRegistry
5 | import org.junit.Assert.assertEquals
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | /**
10 | * Instrumented test, which will execute on an Android device.
11 | *
12 | * See [testing documentation](http://d.android.com/tools/testing).
13 | */
14 | @RunWith(AndroidJUnit4::class)
15 | class ExampleInstrumentedTest {
16 | @Test
17 | fun useAppContext() {
18 | // Context of the app under test.
19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
20 | assertEquals("www.thecodemonks.topten", appContext.packageName)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
27 |
28 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/app/NYTimes.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.app
28 |
29 | import android.app.Application
30 | import dagger.hilt.android.HiltAndroidApp
31 |
32 | @HiltAndroidApp
33 | class NYTimes : Application()
34 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/datastore/UIModeDataStore.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.datastore
28 |
29 | import android.content.Context
30 | import androidx.datastore.core.DataStore
31 | import androidx.datastore.preferences.core.Preferences
32 | import androidx.datastore.preferences.core.booleanPreferencesKey
33 | import androidx.datastore.preferences.core.edit
34 | import androidx.datastore.preferences.createDataStore
35 | import kotlinx.coroutines.flow.Flow
36 | import kotlinx.coroutines.flow.map
37 |
38 | abstract class PrefsDataStore(context: Context, fileName: String) {
39 |
40 | internal val dataStore: DataStore = context.createDataStore(
41 | name = fileName
42 | )
43 | }
44 |
45 | class UIModeDataStore(context: Context) :
46 | PrefsDataStore(
47 | context,
48 | PREF_FILE_UI_MODE
49 | ),
50 | UIModeMutableStore,
51 | UIModeReadStore {
52 |
53 | override suspend fun saveToDataStore(isNightMode: Boolean) {
54 | dataStore.edit { preferences ->
55 | preferences[UI_MODE_KEY] = isNightMode
56 | }
57 | }
58 |
59 | override val uiMode: Flow = dataStore.data
60 | .map { preferences ->
61 | val uiMode = preferences[UI_MODE_KEY] ?: false
62 | uiMode
63 | }
64 |
65 | companion object {
66 | private const val PREF_FILE_UI_MODE = "ui_mode_preference"
67 | private val UI_MODE_KEY = booleanPreferencesKey("ui_mode")
68 | }
69 | }
70 |
71 | interface UIModeMutableStore {
72 | suspend fun saveToDataStore(isNightMode: Boolean)
73 | }
74 |
75 | interface UIModeReadStore {
76 | val uiMode: Flow
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/db/AppDatabase.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.db
28 |
29 | import android.content.Context
30 | import androidx.room.Database
31 | import androidx.room.Room
32 | import androidx.room.RoomDatabase
33 | import www.thecodemonks.techbytes.model.Article
34 |
35 | @Database(
36 | entities = [Article::class],
37 | version = 1,
38 | exportSchema = false
39 | )
40 | abstract class AppDatabase : RoomDatabase(), ArticleDatabase {
41 |
42 | abstract override fun getArticleDao(): ArticleDao
43 |
44 | companion object {
45 | private const val DatabaseName = "articles_db.db"
46 |
47 | @Volatile
48 | private var instance: AppDatabase? = null
49 |
50 | // Check for DB instance if not null then get or insert or else create new DB Instance
51 | operator fun invoke(context: Context) = instance ?: synchronized(this) {
52 | instance ?: createDatabase(context)
53 | .also { instance = it }
54 | }
55 |
56 | // create db instance
57 | private fun createDatabase(context: Context) = Room.databaseBuilder(
58 | context.applicationContext,
59 | AppDatabase::class.java,
60 | DatabaseName
61 | ).build()
62 | }
63 | }
64 |
65 | interface ArticleDatabase {
66 | fun getArticleDao(): ArticleDao
67 | }
68 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/db/ArticleDao.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.db
28 |
29 | import androidx.room.*
30 | import kotlinx.coroutines.flow.Flow
31 | import www.thecodemonks.techbytes.model.Article
32 |
33 | @Dao
34 | interface ArticleDao {
35 |
36 | // insert or update article
37 | @Insert(onConflict = OnConflictStrategy.REPLACE)
38 | suspend fun upsert(article: Article)
39 |
40 | // get all article from db
41 | @Query("SELECT * FROM article")
42 | fun getSavedArticle(): Flow>
43 |
44 | // delete article from db
45 | @Delete
46 | suspend fun deleteArticle(article: Article)
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/di/DataSourceResolver.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.di
28 |
29 | import dagger.Module
30 | import dagger.Provides
31 | import dagger.hilt.InstallIn
32 | import dagger.hilt.components.SingletonComponent
33 | import www.thecodemonks.techbytes.db.ArticleDao
34 | import www.thecodemonks.techbytes.db.ArticleDatabase
35 | import www.thecodemonks.techbytes.repo.ArticleRepository
36 | import www.thecodemonks.techbytes.repo.Repo
37 | import javax.inject.Singleton
38 |
39 | // these modules components are android framework free
40 |
41 | @InstallIn(SingletonComponent::class)
42 | @Module
43 | object DataSourceResolver {
44 |
45 | @Provides
46 | @Singleton
47 | fun provideArticleDao(articleDatabase: ArticleDatabase): ArticleDao {
48 | return articleDatabase.getArticleDao()
49 | }
50 |
51 | // todo check scope
52 | @Provides
53 | @Singleton
54 | fun provideArticleRepository(articleDatabase: ArticleDatabase): ArticleRepository {
55 | return Repo(articleDatabase)
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/di/DomainResolver.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.di
28 |
29 | import dagger.Binds
30 | import dagger.Module
31 | import dagger.hilt.InstallIn
32 | import dagger.hilt.components.SingletonComponent
33 | import www.thecodemonks.techbytes.datastore.UIModeDataStore
34 | import www.thecodemonks.techbytes.datastore.UIModeMutableStore
35 | import www.thecodemonks.techbytes.datastore.UIModeReadStore
36 | import www.thecodemonks.techbytes.db.AppDatabase
37 | import www.thecodemonks.techbytes.db.ArticleDatabase
38 | import javax.inject.Singleton
39 |
40 | // this resolver transforms hard android framework dependencies to android free logic objects
41 |
42 | @Module
43 | @InstallIn(SingletonComponent::class)
44 | abstract class DomainResolver {
45 |
46 | @Binds
47 | @Singleton
48 | abstract fun bindArticleDatabase(appDatabase: AppDatabase): ArticleDatabase
49 |
50 | @Binds
51 | @Singleton
52 | abstract fun bindUIModeMutableStore(uiModeDataStore: UIModeDataStore): UIModeMutableStore
53 |
54 | @Binds
55 | @Singleton
56 | abstract fun bindUIModeReadStore(uiModeDataStore: UIModeDataStore): UIModeReadStore
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/di/FrameworkResolver.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.di
28 |
29 | import android.content.Context
30 | import dagger.Module
31 | import dagger.Provides
32 | import dagger.hilt.InstallIn
33 | import dagger.hilt.android.qualifiers.ApplicationContext
34 | import dagger.hilt.components.SingletonComponent
35 | import www.thecodemonks.techbytes.datastore.UIModeDataStore
36 | import www.thecodemonks.techbytes.db.AppDatabase
37 | import www.thecodemonks.techbytes.utils.NetworkManager
38 | import javax.inject.Singleton
39 |
40 | // this module resolve all the hard android framework dependent objects
41 |
42 | @Module
43 | @InstallIn(SingletonComponent::class)
44 | object FrameworkResolver {
45 |
46 | @Singleton
47 | @Provides
48 | fun providesAppDatabase(@ApplicationContext context: Context): AppDatabase {
49 | return AppDatabase.invoke(context)
50 | }
51 |
52 | @Singleton
53 | @Provides
54 | fun providesUIModelDataStore(@ApplicationContext context: Context): UIModeDataStore {
55 | return UIModeDataStore(context)
56 | }
57 |
58 | @Singleton
59 | @Provides
60 | fun providesNetworkManager(@ApplicationContext context: Context): NetworkManager {
61 | return NetworkManager(context)
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/model/Article.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.model
28 |
29 | import androidx.room.ColumnInfo
30 | import androidx.room.Entity
31 | import androidx.room.PrimaryKey
32 | import java.io.Serializable
33 |
34 | @Entity(
35 | tableName = "article"
36 | )
37 | data class Article(
38 | @PrimaryKey
39 | @ColumnInfo(name = "title")
40 | val title: String = " ",
41 | @ColumnInfo(name = "description")
42 | val description: String? = null,
43 | @ColumnInfo(name = "image")
44 | val image: String? = null,
45 | @ColumnInfo(name = "author")
46 | val author: String? = null,
47 | @ColumnInfo(name = "source")
48 | val source: String? = null
49 | ) : Serializable
50 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/model/Category.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.model
28 |
29 | data class Category(
30 | val title: String? = null,
31 | val source: String? = null
32 | )
33 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/repo/Repo.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.repo
28 |
29 | import kotlinx.coroutines.flow.Flow
30 | import org.jsoup.Jsoup
31 | import www.thecodemonks.techbytes.db.ArticleDatabase
32 | import www.thecodemonks.techbytes.model.Article
33 |
34 | class Repo(private val db: ArticleDatabase) : ArticleRepository {
35 |
36 | // insert or update article
37 | override suspend fun upsertArticle(article: Article) = db.getArticleDao().upsert(article)
38 |
39 | // get saved article
40 | override fun getSavedArticle(): Flow> = db.getArticleDao().getSavedArticle()
41 |
42 | // delete article
43 | override suspend fun deleteArticle(article: Article) = db.getArticleDao().deleteArticle(article)
44 |
45 | // crawl data from ny times by selecting Xpath elements
46 | override fun crawlFromNYTimes(url: String): List {
47 |
48 | val document = Jsoup.connect(url).get()
49 | val articles: MutableList = mutableListOf()
50 |
51 | // Path of articles present in the web
52 | val articleHTML = document.getElementById("stream-panel")
53 | .select("div").select("ol")
54 | .select("div").select("div").select("a")
55 |
56 | // iterate each article to get content
57 | articleHTML.forEach { item ->
58 | val image = item.select("div").select("figure")
59 | .select("div").select("img").attr("src")
60 | val title = item.select("h2").text()
61 | val description = item.select("p").text()
62 | val author = item.select("div").select("p").select("span").text()
63 | val source = item.attr("href")
64 |
65 | // check for null content
66 | if (!image.isNullOrEmpty() || !title.isNullOrEmpty() ||
67 | !description.isNullOrEmpty() || !author.isNullOrEmpty() ||
68 | !source.isNullOrEmpty()
69 | ) {
70 | val article = Article(
71 | title,
72 | description,
73 | image,
74 | author,
75 | source
76 | )
77 | // add iterated articles to list
78 | articles.add(article)
79 | }
80 | }
81 | return articles
82 | }
83 | }
84 |
85 | interface ArticleRepository {
86 | suspend fun upsertArticle(article: Article)
87 | fun getSavedArticle(): Flow>
88 | suspend fun deleteArticle(article: Article)
89 | fun crawlFromNYTimes(url: String): List
90 | }
91 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/ui/about/AboutFragment.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.ui.about
28 |
29 | import android.content.Intent
30 | import android.net.Uri
31 | import android.os.Bundle
32 | import android.view.LayoutInflater
33 | import android.view.View
34 | import android.view.ViewGroup
35 | import androidx.fragment.app.activityViewModels
36 | import dagger.hilt.android.AndroidEntryPoint
37 | import www.thecodemonks.techbytes.BuildConfig
38 | import www.thecodemonks.techbytes.R
39 | import www.thecodemonks.techbytes.databinding.FragmentAboutBinding
40 | import www.thecodemonks.techbytes.ui.base.BaseFragment
41 |
42 | @AndroidEntryPoint
43 | class AboutFragment : BaseFragment() {
44 | override val viewModel: AboutViewModel by activityViewModels()
45 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
46 | super.onViewCreated(view, savedInstanceState)
47 | initViews()
48 | }
49 |
50 | private fun initViews() = with(binding) {
51 | appVersion.text = getString(
52 | R.string.text_app_version,
53 | BuildConfig.VERSION_NAME,
54 | BuildConfig.VERSION_CODE
55 | )
56 |
57 | license.setOnClickListener {
58 | launchBrowser(REPO_LICENSE)
59 | }
60 |
61 | visitURL.setOnClickListener {
62 | launchBrowser(REPO_URL)
63 | }
64 | }
65 |
66 | private fun launchBrowser(url: String) = Intent(Intent.ACTION_VIEW, Uri.parse(url)).also {
67 | startActivity(it)
68 | }
69 |
70 | override fun getViewBinding(
71 | inflater: LayoutInflater,
72 | container: ViewGroup?
73 | ) = FragmentAboutBinding.inflate(inflater, container, false)
74 |
75 | companion object {
76 | const val REPO_URL = "https://github.com/TheCodeMonks/NYTimes-App"
77 | const val REPO_LICENSE = "https://github.com/TheCodeMonks/NYTimes-App/blob/master/LICENSE"
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/ui/about/AboutViewModel.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.ui.about
28 |
29 | import androidx.lifecycle.ViewModel
30 |
31 | class AboutViewModel : ViewModel()
32 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/ui/adapter/CategoryAdapter.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.ui.adapter
28 |
29 | import android.graphics.BlendMode
30 | import android.graphics.BlendModeColorFilter
31 | import android.graphics.PorterDuff
32 | import android.graphics.drawable.Drawable
33 | import android.os.Build
34 | import android.view.LayoutInflater
35 | import android.view.ViewGroup
36 | import androidx.core.content.ContextCompat
37 | import androidx.recyclerview.widget.RecyclerView
38 | import www.thecodemonks.techbytes.R
39 | import www.thecodemonks.techbytes.databinding.ItemPostCategoryBinding
40 | import www.thecodemonks.techbytes.model.Category
41 |
42 | class CategoryAdapter(private val category: MutableList) :
43 | RecyclerView.Adapter() {
44 |
45 | private var selectedItem: Int = -1
46 |
47 | inner class CategoryViewHolder(val binding: ItemPostCategoryBinding) :
48 | RecyclerView.ViewHolder(binding.root)
49 |
50 | override fun onCreateViewHolder(
51 | parent: ViewGroup,
52 | viewType: Int
53 | ): CategoryViewHolder {
54 | val binding =
55 | ItemPostCategoryBinding.inflate(LayoutInflater.from(parent.context), parent, false)
56 | return CategoryViewHolder(binding)
57 | }
58 |
59 | override fun getItemCount(): Int {
60 | return category.size
61 | }
62 |
63 | override fun onBindViewHolder(holder: CategoryViewHolder, position: Int) {
64 | holder.binding.apply {
65 |
66 | itemCategoryTitle.text = category[position].title
67 |
68 | // on item click
69 | holder.itemView.setOnClickListener {
70 | onItemClickListener?.let {
71 | it(category[position])
72 |
73 | if (selectedItem == position) {
74 | notifyItemChanged(position)
75 | return@setOnClickListener
76 | }
77 |
78 | selectedItem = position
79 | notifyDataSetChanged()
80 | }
81 | }
82 |
83 | // if item selected then change it's state color
84 | when (selectedItem) {
85 | position -> {
86 | itemCategoryTitle.setTextColor(
87 | ContextCompat.getColor(
88 | itemCategoryTitle.context,
89 | R.color.white
90 | )
91 | )
92 |
93 | MyDrawableCompat.setColorFilter(
94 | itemCategoryTitle.background,
95 | ContextCompat.getColor(root.context, R.color.design_default_color_primary)
96 | )
97 | }
98 | else -> {
99 | itemCategoryTitle.setTextColor(
100 | ContextCompat.getColor(
101 | itemCategoryTitle.context,
102 | R.color.categoryText
103 | )
104 | )
105 | MyDrawableCompat.setColorFilter(
106 | itemCategoryTitle.background,
107 | ContextCompat.getColor(root.context, R.color.blue_smoke)
108 | )
109 | }
110 | }
111 | }
112 | }
113 |
114 | // on item click listener
115 | private var onItemClickListener: ((Category) -> Unit)? = null
116 | fun setOnItemClickListener(listener: (Category) -> Unit) {
117 | onItemClickListener = listener
118 | }
119 |
120 | // check if android version is greater than Q -> color filter else use set color filter
121 | object MyDrawableCompat {
122 | fun setColorFilter(drawable: Drawable, color: Int) {
123 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
124 | drawable.colorFilter = BlendModeColorFilter(color, BlendMode.SRC_ATOP)
125 | } else {
126 | drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP)
127 | }
128 | }
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/ui/adapter/NewsAdapter.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.ui.adapter
28 |
29 | import android.view.LayoutInflater
30 | import android.view.View
31 | import android.view.ViewGroup
32 | import androidx.recyclerview.widget.AsyncListDiffer
33 | import androidx.recyclerview.widget.DiffUtil
34 | import androidx.recyclerview.widget.RecyclerView
35 | import coil.load
36 | import coil.transform.RoundedCornersTransformation
37 | import www.thecodemonks.techbytes.databinding.ItemPostArticleBinding
38 | import www.thecodemonks.techbytes.model.Article
39 |
40 | class NewsAdapter : RecyclerView.Adapter() {
41 |
42 | private val differCallback = object : DiffUtil.ItemCallback() {
43 | override fun areItemsTheSame(oldItem: Article, newItem: Article): Boolean {
44 | return oldItem.source == newItem.source
45 | }
46 |
47 | override fun areContentsTheSame(oldItem: Article, newItem: Article): Boolean {
48 | return oldItem == newItem
49 | }
50 | }
51 |
52 | val differ = AsyncListDiffer(this, differCallback)
53 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NewsVH {
54 | val binding =
55 | ItemPostArticleBinding.inflate(LayoutInflater.from(parent.context), parent, false)
56 | return NewsVH(binding)
57 | }
58 |
59 | override fun getItemCount(): Int {
60 | return differ.currentList.size
61 | }
62 |
63 | override fun onBindViewHolder(holder: NewsVH, position: Int) {
64 |
65 | val item = differ.currentList[position]
66 | holder.binding.apply {
67 |
68 | // TODO clean logic
69 | if (item.title.isBlank() || item.description.isNullOrBlank() ||
70 | item.image.isNullOrBlank()
71 | ) {
72 | itemArticleTitle.visibility = View.GONE
73 | itemPostDescription.visibility = View.GONE
74 | itemPostAuthor.visibility = View.GONE
75 | itemArticleImage.visibility = View.GONE
76 | } else {
77 | itemArticleTitle.text = item.title
78 | itemPostDescription.text = item.description
79 | itemPostAuthor.text = item.author.toString().ifBlank { "Unknown" }
80 | itemArticleImage.load(item.image) {
81 | crossfade(true)
82 | crossfade(200)
83 | transformations(
84 | RoundedCornersTransformation(
85 | 12f,
86 | 12f,
87 | 12f,
88 | 12f
89 | )
90 | )
91 | }
92 | }
93 |
94 | // on item click
95 | holder.itemView.setOnClickListener {
96 | onItemClickListener?.let { it(item) }
97 | }
98 | }
99 | }
100 |
101 | inner class NewsVH(val binding: ItemPostArticleBinding) : RecyclerView.ViewHolder(binding.root)
102 |
103 | // on item click listener
104 | private var onItemClickListener: ((Article) -> Unit)? = null
105 | fun setOnItemClickListener(listener: (Article) -> Unit) {
106 | onItemClickListener = listener
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/ui/base/BaseActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.ui.base
28 |
29 | import android.os.Bundle
30 | import androidx.activity.viewModels
31 | import androidx.appcompat.app.AppCompatActivity
32 | import androidx.navigation.NavController
33 | import androidx.navigation.fragment.NavHostFragment
34 | import androidx.navigation.ui.NavigationUI
35 | import androidx.work.Constraints
36 | import androidx.work.ExistingPeriodicWorkPolicy.KEEP
37 | import androidx.work.NetworkType
38 | import androidx.work.PeriodicWorkRequestBuilder
39 | import androidx.work.WorkManager
40 | import dagger.hilt.android.AndroidEntryPoint
41 | import www.thecodemonks.techbytes.R
42 | import www.thecodemonks.techbytes.databinding.ActivityBaseBinding
43 | import www.thecodemonks.techbytes.ui.viewmodel.ArticleViewModel
44 | import www.thecodemonks.techbytes.worker.MyWorker
45 | import java.util.concurrent.TimeUnit
46 |
47 | @AndroidEntryPoint
48 | class BaseActivity : AppCompatActivity() {
49 |
50 | // todo test scope and reference
51 | private val viewModel: ArticleViewModel by viewModels()
52 |
53 | private lateinit var navController: NavController
54 |
55 | override fun onCreate(savedInstanceState: Bundle?) {
56 | super.onCreate(savedInstanceState)
57 |
58 | val binding = ActivityBaseBinding.inflate(layoutInflater)
59 |
60 | setContentView(binding.root)
61 | setSupportActionBar(binding.toolbar)
62 |
63 | // todo integrate with Hilt
64 | // setup workManager
65 | initWorker()
66 |
67 | // init nav controller with back action button
68 | val navHostFragment =
69 | supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
70 | navController = navHostFragment.navController
71 | NavigationUI.setupActionBarWithNavController(this, navController)
72 | }
73 |
74 | // todo integrate with Hilt
75 | private fun initWorker() {
76 | // worker constraints
77 | val constraints = Constraints.Builder()
78 | .setRequiredNetworkType(NetworkType.CONNECTED)
79 | .build()
80 |
81 | // periodic worker for every 15 minutes
82 | val notificationWorkRequest =
83 | PeriodicWorkRequestBuilder(15, TimeUnit.MINUTES)
84 | .setConstraints(constraints)
85 | .build()
86 |
87 | // enqueue work
88 | val workManager = WorkManager.getInstance(applicationContext)
89 | workManager.enqueueUniquePeriodicWork(JOB_TAG, KEEP, notificationWorkRequest)
90 | }
91 |
92 | override fun onSupportNavigateUp(): Boolean {
93 | navController.navigateUp()
94 | return super.onSupportNavigateUp()
95 | }
96 |
97 | companion object {
98 | const val JOB_TAG = "articlesWorkerTag"
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/ui/base/BaseFragment.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.ui.base
28 |
29 | import android.content.Context
30 | import android.os.Bundle
31 | import android.view.LayoutInflater
32 | import android.view.View
33 | import android.view.ViewGroup
34 | import android.widget.Toast
35 | import androidx.fragment.app.Fragment
36 | import androidx.lifecycle.ViewModel
37 | import androidx.viewbinding.ViewBinding
38 |
39 | abstract class BaseFragment : Fragment() {
40 |
41 | private var _binding: VB? = null
42 | protected val binding get() = _binding!!
43 |
44 | protected abstract val viewModel: VM
45 |
46 | override fun onCreateView(
47 | inflater: LayoutInflater,
48 | container: ViewGroup?,
49 | savedInstanceState: Bundle?
50 | ): View? {
51 | _binding = getViewBinding(inflater, container)
52 | return binding.root
53 | }
54 |
55 | protected abstract fun getViewBinding(inflater: LayoutInflater, container: ViewGroup?): VB
56 |
57 | fun toast(message: String) {
58 | Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
59 | }
60 |
61 | fun applicationContext(): Context = requireActivity().applicationContext
62 |
63 | override fun onDestroy() {
64 | super.onDestroy()
65 | _binding = null
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/ui/details/ArticleDetailsFragment.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.ui.details
28 |
29 | import android.os.Build
30 | import android.os.Bundle
31 | import android.view.LayoutInflater
32 | import android.view.Menu
33 | import android.view.MenuInflater
34 | import android.view.MenuItem
35 | import android.view.View
36 | import android.view.ViewGroup
37 | import androidx.core.app.ShareCompat
38 | import androidx.fragment.app.activityViewModels
39 | import androidx.navigation.fragment.navArgs
40 | import dagger.hilt.android.AndroidEntryPoint
41 | import www.thecodemonks.techbytes.R
42 | import www.thecodemonks.techbytes.databinding.FragmentArticleDetailsBinding
43 | import www.thecodemonks.techbytes.model.Article
44 | import www.thecodemonks.techbytes.ui.base.BaseFragment
45 | import www.thecodemonks.techbytes.ui.viewmodel.ArticleViewModel
46 | import www.thecodemonks.techbytes.utils.Constants
47 |
48 | @AndroidEntryPoint
49 | class ArticleDetailsFragment : BaseFragment() {
50 |
51 | override val viewModel: ArticleViewModel by activityViewModels()
52 | private val args: ArticleDetailsFragmentArgs by navArgs()
53 | private var completeUrl: String? = null
54 |
55 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
56 | super.onViewCreated(view, savedInstanceState)
57 |
58 | setHasOptionsMenu(true)
59 |
60 | // receive bundle here
61 | val bundle = args.article
62 | completeUrl = Constants.URL.plus(bundle.source)
63 |
64 | // webView with url has param
65 | binding.webView.apply {
66 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
67 | webViewClient = webViewClient
68 | }
69 | loadUrl(completeUrl!!)
70 | }
71 |
72 | binding.btnSavedArticle.setOnClickListener {
73 | val article = Article(
74 | bundle.title,
75 | bundle.description,
76 | bundle.image,
77 | bundle.author,
78 | bundle.source
79 | )
80 | viewModel.upsertArticle(article).also {
81 | toast(getString(R.string.successfully_saved))
82 | }
83 | }
84 | }
85 |
86 | override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
87 | // Inflate the menu; this adds items to the action bar if it is present.
88 | inflater.inflate(R.menu.share_menu, menu)
89 | }
90 |
91 | override fun onOptionsItemSelected(item: MenuItem): Boolean {
92 | // Handle action bar item clicks here.
93 | return when (item.itemId) {
94 | R.id.action_share -> {
95 | val shareMsg = getString(
96 | R.string.share_message,
97 | args.article.title,
98 | completeUrl
99 | )
100 |
101 | val intent = ShareCompat.IntentBuilder.from(requireActivity())
102 | .setType("text/plain")
103 | .setText(shareMsg)
104 | .intent
105 |
106 | if (intent.resolveActivity(requireActivity().packageManager) != null) {
107 | startActivity(intent)
108 | }
109 | true
110 | }
111 | else -> super.onOptionsItemSelected(item)
112 | }
113 | }
114 |
115 | override fun getViewBinding(
116 | inflater: LayoutInflater,
117 | container: ViewGroup?
118 | ) = FragmentArticleDetailsBinding.inflate(inflater, container, false)
119 | }
120 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/ui/viewmodel/ArticleViewModel.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.ui.viewmodel
28 |
29 | import android.app.Application
30 | import androidx.hilt.lifecycle.ViewModelInject
31 | import androidx.lifecycle.AndroidViewModel
32 | import androidx.lifecycle.LiveData
33 | import androidx.lifecycle.MutableLiveData
34 | import androidx.lifecycle.asLiveData
35 | import androidx.lifecycle.viewModelScope
36 | import kotlinx.coroutines.Dispatchers.IO
37 | import kotlinx.coroutines.launch
38 | import www.thecodemonks.techbytes.datastore.UIModeMutableStore
39 | import www.thecodemonks.techbytes.datastore.UIModeReadStore
40 | import www.thecodemonks.techbytes.model.Article
41 | import www.thecodemonks.techbytes.repo.ArticleRepository
42 | import www.thecodemonks.techbytes.utils.Constants
43 | import www.thecodemonks.techbytes.utils.NetworkManager
44 |
45 | class ArticleViewModel @ViewModelInject constructor(
46 | application: Application,
47 | private val repo: ArticleRepository,
48 | private val uiModeEdit: UIModeMutableStore,
49 | val uiModeRead: UIModeReadStore,
50 | private val networkManager: NetworkManager,
51 | ) : AndroidViewModel(application) {
52 |
53 | private val _articles = MutableLiveData>()
54 | val articles: LiveData>
55 | get() = _articles
56 |
57 | val networkObserver = networkManager.observeConnectionStatus
58 |
59 | val currentTopic: MutableLiveData by lazy {
60 | MutableLiveData().defaultTopic(Constants.NY_TECH)
61 | }
62 |
63 | // save article
64 | fun upsertArticle(article: Article) = viewModelScope.launch {
65 | repo.upsertArticle(article)
66 | }
67 |
68 | // get saved article
69 | fun getSavedArticle() = repo.getSavedArticle().asLiveData()
70 |
71 | // save article
72 | fun deleteArticle(article: Article) = viewModelScope.launch {
73 | repo.deleteArticle(article)
74 | }
75 |
76 | private var currentQueryUrl = ""
77 |
78 | // crawl data from NY times
79 | fun crawlFromNYTimes(url: String) {
80 | currentQueryUrl = url
81 | if (networkObserver.value == true) {
82 | viewModelScope.launch(IO) {
83 | _articles.postValue(repo.crawlFromNYTimes(url))
84 | }
85 | }
86 | }
87 |
88 | fun reCrawlFromNYTimes(refreshFailed: () -> Unit = {}) {
89 | if (networkObserver.value == true) {
90 | viewModelScope.launch(IO) {
91 | _articles.postValue(repo.crawlFromNYTimes(currentQueryUrl))
92 | }
93 | } else {
94 | refreshFailed.invoke()
95 | }
96 | }
97 |
98 | // Save to DataStore
99 | fun saveToDataStore(isNightMode: Boolean) = viewModelScope.launch(IO) {
100 | uiModeEdit.saveToDataStore(isNightMode)
101 | }
102 |
103 | // set default topic when opening
104 | private fun MutableLiveData.defaultTopic(initialValue: T) =
105 | apply { setValue(initialValue) }
106 | }
107 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/utils/Constants.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.utils
28 |
29 | object Constants {
30 | const val URL = "https://www.nytimes.com"
31 | const val NY_SCIENCE = "https://www.nytimes.com/section/science"
32 | const val NY_TECH = "https://www.nytimes.com/section/technology"
33 | const val NY_BUSINESS = "https://www.nytimes.com/section/business/smallbusiness"
34 | const val NY_YOURMONEY = "https://www.nytimes.com/section/your-money"
35 | const val NY_EDUCATION = "https://www.nytimes.com/section/education"
36 | const val NY_SPORTS = "https://www.nytimes.com/section/sports/soccer"
37 | const val NY_SPACE = "https://www.nytimes.com/section/science/space"
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/utils/NetworkManager.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.utils
28 |
29 | import android.content.Context
30 | import android.net.ConnectivityManager
31 | import android.net.Network
32 | import android.net.NetworkCapabilities
33 | import android.net.NetworkRequest
34 | import android.os.Build
35 | import androidx.core.content.getSystemService
36 | import androidx.lifecycle.LiveData
37 | import androidx.lifecycle.MutableLiveData
38 |
39 | /**
40 | * Network Manager, extends capabilities of ConnectivityManager#NetworkCallback()
41 | * by providing a observable callback on network status
42 | *
43 | * Author : [https://github.com/ch8n]
44 | * website : [https://chetangupta.net]
45 | * Creation Date : 4-08-2020
46 | */
47 | class NetworkManager(context: Context) : ConnectivityManager.NetworkCallback() {
48 |
49 | private val _connectionStatusLiveData: MutableLiveData = MutableLiveData()
50 | val observeConnectionStatus: LiveData = _connectionStatusLiveData
51 |
52 | private val appContext: Context = context.applicationContext
53 |
54 | init {
55 | val connectivityManager = appContext.getSystemService()
56 |
57 | if (connectivityManager != null) {
58 | connectivityManager.registerNetworkCallbackCompact(this)
59 |
60 | val connectionStatus = connectivityManager.allNetworks.any { network ->
61 | val networkCapabilities = connectivityManager.getNetworkCapabilities(network)
62 | return@any networkCapabilities?.hasCapability(
63 | NetworkCapabilities.NET_CAPABILITY_INTERNET
64 | ) == true
65 | }
66 |
67 | _connectionStatusLiveData.value = connectionStatus
68 | }
69 | }
70 |
71 | override fun onAvailable(network: Network) {
72 | super.onAvailable(network)
73 | _connectionStatusLiveData.postValue(true)
74 | }
75 |
76 | override fun onLost(network: Network) {
77 | super.onLost(network)
78 | _connectionStatusLiveData.postValue(false)
79 | }
80 |
81 | private fun ConnectivityManager.registerNetworkCallbackCompact(networkManager: NetworkManager) {
82 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
83 | registerDefaultNetworkCallback(networkManager)
84 | } else {
85 | val builder = NetworkRequest.Builder()
86 | registerNetworkCallback(builder.build(), networkManager)
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/utils/NetworkUtils.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.utils
28 |
29 | import android.content.Context
30 | import android.net.ConnectivityManager
31 | import android.net.Network
32 | import android.net.NetworkCapabilities
33 | import android.net.NetworkRequest
34 | import android.os.Build
35 | import androidx.lifecycle.LiveData
36 | import androidx.lifecycle.MutableLiveData
37 |
38 | /**
39 | * Network Utility to detect availability or unavailability of Internet connection
40 | */
41 | object NetworkUtils : ConnectivityManager.NetworkCallback() {
42 |
43 | private val networkLiveData: MutableLiveData = MutableLiveData()
44 |
45 | /**
46 | * Returns instance of [LiveData] which can be observed for connectivity changes.
47 | */
48 | fun observeConnectivity(context: Context): LiveData {
49 | val connectivityManager =
50 | context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
51 |
52 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
53 | connectivityManager.registerDefaultNetworkCallback(this)
54 | } else {
55 | val builder = NetworkRequest.Builder()
56 | connectivityManager.registerNetworkCallback(builder.build(), this)
57 | }
58 |
59 | // Retrieve current status of connectivity
60 | val isConnected = isConnected(connectivityManager)
61 |
62 | networkLiveData.postValue(isConnected)
63 |
64 | return networkLiveData
65 | }
66 |
67 | override fun onAvailable(network: Network) {
68 | networkLiveData.postValue(true)
69 | }
70 |
71 | override fun onLost(network: Network) {
72 | networkLiveData.postValue(false)
73 | }
74 | }
75 |
76 | private fun isConnected(connectivityManager: ConnectivityManager): Boolean {
77 | var isConnected = false
78 |
79 | // Retrieve current status of connectivity
80 | connectivityManager.allNetworks.forEach { network ->
81 | val networkCapability = connectivityManager.getNetworkCapabilities(network)
82 |
83 | networkCapability?.let {
84 | if (it.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
85 | isConnected = true
86 | return@forEach
87 | }
88 | }
89 | }
90 | return isConnected
91 | }
92 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/utils/SpacesItemDecorator.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.utils
28 |
29 | import android.content.res.Resources
30 | import android.graphics.Rect
31 | import android.view.View
32 | import androidx.recyclerview.widget.LinearLayoutManager
33 | import androidx.recyclerview.widget.RecyclerView
34 |
35 | class SpacesItemDecorator(space: Int) : RecyclerView.ItemDecoration() {
36 |
37 | private val space: Int = space.dp
38 |
39 | override fun getItemOffsets(
40 | outRect: Rect,
41 | view: View,
42 | parent: RecyclerView,
43 | state: RecyclerView.State
44 | ) {
45 | val orientation = (parent.layoutManager as? LinearLayoutManager)?.orientation
46 | ?: LinearLayoutManager.VERTICAL
47 | if (orientation == LinearLayoutManager.HORIZONTAL) {
48 | when (parent.getChildLayoutPosition(view)) {
49 | 0 -> {
50 | outRect.left = space
51 | outRect.right = space
52 | }
53 | else -> outRect.right = space
54 | }
55 | } else {
56 | when (parent.getChildLayoutPosition(view)) {
57 | 0 -> {
58 | outRect.top = space
59 | outRect.left = space
60 | outRect.right = space
61 | outRect.bottom = space
62 | }
63 | else -> {
64 | outRect.left = space
65 | outRect.right = space
66 | outRect.bottom = space
67 | }
68 | }
69 | }
70 | }
71 | }
72 |
73 | val Int.dp: Int get() = (this * Resources.getSystem().displayMetrics.density).toInt()
74 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/utils/ViewExt.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.utils
28 |
29 | import android.content.Context
30 | import android.view.View
31 | import android.widget.TextView
32 | import androidx.annotation.DrawableRes
33 | import androidx.core.content.ContextCompat
34 |
35 | fun View.show() {
36 | visibility = View.VISIBLE
37 | }
38 |
39 | fun View.hide() {
40 | visibility = View.GONE
41 | }
42 |
43 | fun View.setVisible(isVisible: Boolean) {
44 | if (isVisible) show() else hide()
45 | }
46 |
47 | fun TextView.setDrawableLeft(@DrawableRes id: Int = 0) {
48 | this.setCompoundDrawablesWithIntrinsicBounds(id, 0, 0, 0)
49 | }
50 |
51 | fun Context.getColorCompat(color: Int) = ContextCompat.getColor(this, color)
52 |
--------------------------------------------------------------------------------
/app/src/main/java/www/thecodemonks/techbytes/worker/MyWorker.kt:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | package www.thecodemonks.techbytes.worker
28 |
29 | import android.app.NotificationChannel
30 | import android.app.NotificationManager
31 | import android.app.PendingIntent
32 | import android.content.Context
33 | import android.content.Intent
34 | import android.media.RingtoneManager
35 | import android.os.Build
36 | import android.util.Log
37 | import androidx.core.app.NotificationCompat
38 | import androidx.core.content.ContextCompat
39 | import androidx.work.Worker
40 | import androidx.work.WorkerParameters
41 | import www.thecodemonks.techbytes.R
42 | import www.thecodemonks.techbytes.db.AppDatabase
43 | import www.thecodemonks.techbytes.repo.Repo
44 | import www.thecodemonks.techbytes.ui.base.BaseActivity
45 | import www.thecodemonks.techbytes.utils.Constants
46 |
47 | class MyWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
48 |
49 | private fun showNotification(title: String, description: String) {
50 |
51 | val intent = Intent(applicationContext, BaseActivity::class.java)
52 | intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
53 | val pendingIntent = PendingIntent.getActivity(
54 | applicationContext,
55 | 0,
56 | intent,
57 | PendingIntent.FLAG_ONE_SHOT
58 | )
59 |
60 | val channelId = applicationContext.getString(R.string.default_notification_channel_id)
61 | val channelName = applicationContext.getString(R.string.default_notification_channel_name)
62 | val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
63 | val notificationBuilder = NotificationCompat.Builder(applicationContext, channelId)
64 | .setColor(ContextCompat.getColor(applicationContext, R.color.black))
65 | .setSmallIcon(R.drawable.ic_ny_notification_icon)
66 | .setContentTitle(title)
67 | .setContentText(description)
68 | .setAutoCancel(true)
69 | .setPriority(NotificationCompat.PRIORITY_DEFAULT)
70 | .setSound(defaultSoundUri)
71 | .setContentIntent(pendingIntent)
72 |
73 | val notificationManager =
74 | applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
75 |
76 | // For android OREO notification channel is needed
77 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
78 | val channel = NotificationChannel(
79 | channelId,
80 | channelName,
81 | NotificationManager.IMPORTANCE_HIGH
82 | )
83 | notificationManager.createNotificationChannel(channel)
84 | }
85 |
86 | notificationManager.notify(0, notificationBuilder.build())
87 | }
88 |
89 | override fun doWork(): Result {
90 |
91 | val repository = Repo(AppDatabase(applicationContext))
92 | val result = repository.crawlFromNYTimes(Constants.NY_TECH).toList()
93 |
94 | return if (result.isNullOrEmpty()) {
95 | Log.d(javaClass.simpleName, "Work Failed. Retrying...")
96 | Result.retry()
97 | } else {
98 | val title = result[0].title
99 | val description = result[0].description.toString()
100 | showNotification(title, description)
101 | Log.d(javaClass.simpleName, "Notification Displayed!")
102 | Log.d(javaClass.simpleName, "Work Succeed...")
103 |
104 | Result.success()
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/slide_in_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
27 |
28 |
30 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/slide_in_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
27 |
28 |
30 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/slide_out_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
27 |
28 |
30 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/slide_out_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
27 |
28 |
30 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_bookmark.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bookmarks.xml:
--------------------------------------------------------------------------------
1 |
26 |
27 |
32 |
39 |
46 |
47 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_day.xml:
--------------------------------------------------------------------------------
1 |
26 |
27 |
32 |
39 |
46 |
53 |
54 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_empty.xml:
--------------------------------------------------------------------------------
1 |
26 |
27 |
32 |
35 |
38 |
41 |
44 |
47 |
50 |
53 |
56 |
59 |
62 |
65 |
68 |
71 |
74 |
77 |
80 |
83 |
86 |
89 |
92 |
95 |
98 |
101 |
104 |
105 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_internet_off.xml:
--------------------------------------------------------------------------------
1 |
26 |
27 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_internet_on.xml:
--------------------------------------------------------------------------------
1 |
26 |
27 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_night.xml:
--------------------------------------------------------------------------------
1 |
26 |
27 |
32 |
39 |
46 |
47 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_ny_notification_icon.xml:
--------------------------------------------------------------------------------
1 |
26 |
27 |
32 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_outline_dark.xml:
--------------------------------------------------------------------------------
1 |
26 |
27 |
33 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_share.xml:
--------------------------------------------------------------------------------
1 |
26 |
27 |
32 |
39 |
46 |
53 |
60 |
67 |
68 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/nytimes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeMonks/NYTimes-App/f74e3820d68e29f9ac7feecb5fdf58725272480f/app/src/main/res/drawable/nytimes.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/text_chip_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/font/gilroybold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeMonks/NYTimes-App/f74e3820d68e29f9ac7feecb5fdf58725272480f/app/src/main/res/font/gilroybold.ttf
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_base.xml:
--------------------------------------------------------------------------------
1 |
26 |
27 |
35 |
36 |
42 |
43 |
47 |
48 |
49 |
50 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_empty_state_layout.xml:
--------------------------------------------------------------------------------
1 |
26 |
27 |
32 |
33 |
39 |
40 |
52 |
53 |
54 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_about.xml:
--------------------------------------------------------------------------------
1 |
26 |
32 |
33 |
43 |
44 |
55 |
56 |
57 |
66 |
67 |
68 |
79 |
80 |
81 |
91 |
92 |
93 |
104 |
105 |
106 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_article_details.xml:
--------------------------------------------------------------------------------
1 |
26 |
27 |
32 |
33 |
37 |
38 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_articles.xml:
--------------------------------------------------------------------------------
1 |
26 |
27 |
34 |
35 |
45 |
46 |
54 |
55 |
56 |
60 |
61 |
64 |
65 |
73 |
74 |
86 |
87 |
96 |
97 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_bookmarks.xml:
--------------------------------------------------------------------------------
1 |
26 |
27 |
34 |
35 |
39 |
40 |
47 |
48 |
49 |
50 |
51 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_post_article.xml:
--------------------------------------------------------------------------------
1 |
26 |
27 |
34 |
35 |
44 |
45 |
52 |
53 |
64 |
65 |
74 |
75 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_post_category.xml:
--------------------------------------------------------------------------------
1 |
2 |
27 |
28 |
33 |
34 |
35 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
27 |
28 |
50 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/share_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeMonks/NYTimes-App/f74e3820d68e29f9ac7feecb5fdf58725272480f/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeMonks/NYTimes-App/f74e3820d68e29f9ac7feecb5fdf58725272480f/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeMonks/NYTimes-App/f74e3820d68e29f9ac7feecb5fdf58725272480f/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeMonks/NYTimes-App/f74e3820d68e29f9ac7feecb5fdf58725272480f/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeMonks/NYTimes-App/f74e3820d68e29f9ac7feecb5fdf58725272480f/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeMonks/NYTimes-App/f74e3820d68e29f9ac7feecb5fdf58725272480f/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeMonks/NYTimes-App/f74e3820d68e29f9ac7feecb5fdf58725272480f/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeMonks/NYTimes-App/f74e3820d68e29f9ac7feecb5fdf58725272480f/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeMonks/NYTimes-App/f74e3820d68e29f9ac7feecb5fdf58725272480f/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeMonks/NYTimes-App/f74e3820d68e29f9ac7feecb5fdf58725272480f/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/navigation/nav_graph.xml:
--------------------------------------------------------------------------------
1 |
2 |
27 |
28 |
33 |
34 |
39 |
46 |
53 |
56 |
57 |
62 |
65 |
66 |
71 |
74 |
75 |
80 |
81 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
27 |
28 |
29 | @color/black
30 | @color/purple_200
31 | @color/white
32 | #121212
33 | #ffffff
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
27 |
28 |
29 | Share Article
30 | Article saved successfully!
31 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | false
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
27 |
28 |
29 | #FFBB86FC
30 | #FF6200EE
31 | #FF3700B3
32 | #FF03DAC5
33 | #FF018786
34 | #FF000000
35 | #FFFFFFFF
36 | #f3f7f9
37 | #000000
38 |
39 |
40 | @color/white
41 | @color/purple_500
42 | @color/purple_700
43 | @color/white
44 | @color/teal_200
45 | @color/teal_700
46 | @color/black
47 |
48 | #6fcf97
49 | #eb5757
50 |
51 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimen.xml:
--------------------------------------------------------------------------------
1 |
26 |
27 |
28 |
29 | 0dp
30 | 4dp
31 | 8dp
32 | 12dp
33 | 16dp
34 | 24dp
35 | 32dp
36 | 48dp
37 | 64dp
38 | 250dp
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
26 |
27 |
28 | NY Times
29 | Facebook Said Not to Consider Banning Political Ads
30 | The social network has been under intense pressure for allowing misinformation and hate speech to spread on its site.
31 | By Sanju S
32 |
33 |
34 | \"%s\"\n\n source: %s. \n\nVisit: https://github.com/TheCodeMonks/NYTimes-App
35 |
36 |
37 | Bookmark
38 | Night Mode Switch
39 |
40 | Bookmarks
41 | No bookmarks yet
42 | Hello blank fragment
43 |
44 |
45 | 1
46 | Ny Times
47 |
48 | No internet connection
49 | You\'re back online
50 | Share Article
51 | Article saved successfully!
52 | Oops!, It\'s Empty
53 | There are no bookmarks found right now
54 | About
55 |
56 |
57 |
58 | Licensed Under MIT License
59 | Visit
60 | https://github.com/TheCodeMonks/NYTimes-App
61 | v%s (%d)
62 |
63 |
64 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
26 |
27 |
28 |
29 |
33 |
34 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
26 |
27 |
28 |
29 | true
30 |
31 |
51 |
52 |
55 |
56 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/fragment_articles_scene.xml:
--------------------------------------------------------------------------------
1 |
26 |
27 |
29 |
30 |
31 |
38 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/fragment_bookmarks_scene.xml:
--------------------------------------------------------------------------------
1 |
26 |
27 |
29 |
30 |
31 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/app/src/test/java/www/thecodemonks/techbytes/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package www.thecodemonks.techbytes
2 |
3 | import org.junit.Assert.assertEquals
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * See [testing documentation](http://d.android.com/tools/testing).
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * MIT License
4 | * *
5 | * * Copyright (c) 2020 Spikey Sanju
6 | * *
7 | * * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * * of this software and associated documentation files (the "Software"), to deal
9 | * * in the Software without restriction, including without limitation the rights
10 | * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * * copies of the Software, and to permit persons to whom the Software is
12 | * * furnished to do so, subject to the following conditions:
13 | * *
14 | * * The above copyright notice and this permission notice shall be included in all
15 | * * copies or substantial portions of the Software.
16 | * *
17 | * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * * SOFTWARE.
24 | *
25 | */
26 |
27 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
28 | buildscript {
29 |
30 | //versions
31 | ext.kotlin_version = "1.4.21"
32 | ext.hilt_version = "2.30.1-alpha"
33 | ext.hilt_support = "1.0.0-alpha02"
34 |
35 | repositories {
36 | google()
37 | jcenter()
38 | }
39 | dependencies {
40 | classpath 'com.android.tools.build:gradle:4.2.0-beta05'
41 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
42 | classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.2"
43 | classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
44 | }
45 | }
46 |
47 | plugins {
48 | id "org.jlleitschuh.gradle.ktlint" version "9.4.1"
49 | }
50 |
51 | allprojects {
52 | repositories {
53 | google()
54 | jcenter()
55 | }
56 | apply plugin: "org.jlleitschuh.gradle.ktlint"
57 | }
58 |
59 | task clean(type: Delete) {
60 | delete rootProject.buildDir
61 | }
62 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # 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 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeMonks/NYTimes-App/f74e3820d68e29f9ac7feecb5fdf58725272480f/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #
2 | # /*
3 | # * MIT License
4 | # *
5 | # * Copyright (c) 2020 Spikey Sanju
6 | # *
7 | # * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | # * of this software and associated documentation files (the "Software"), to deal
9 | # * in the Software without restriction, including without limitation the rights
10 | # * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | # * copies of the Software, and to permit persons to whom the Software is
12 | # * furnished to do so, subject to the following conditions:
13 | # *
14 | # * The above copyright notice and this permission notice shall be included in all
15 | # * copies or substantial portions of the Software.
16 | # *
17 | # * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | # * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | # * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | # * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | # * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | # * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | # * SOFTWARE.
24 | # */
25 | #
26 |
27 | #Sat Jan 09 01:55:26 IST 2021
28 | distributionBase=GRADLE_USER_HOME
29 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
30 | distributionPath=wrapper/dists
31 | zipStorePath=wrapper/dists
32 | zipStoreBase=GRADLE_USER_HOME
33 |
--------------------------------------------------------------------------------
/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 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
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 Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/screenshots/articledetails.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeMonks/NYTimes-App/f74e3820d68e29f9ac7feecb5fdf58725272480f/screenshots/articledetails.png
--------------------------------------------------------------------------------
/screenshots/articles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeMonks/NYTimes-App/f74e3820d68e29f9ac7feecb5fdf58725272480f/screenshots/articles.png
--------------------------------------------------------------------------------
/screenshots/bookmarks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeMonks/NYTimes-App/f74e3820d68e29f9ac7feecb5fdf58725272480f/screenshots/bookmarks.png
--------------------------------------------------------------------------------
/screenshots/darkmode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeMonks/NYTimes-App/f74e3820d68e29f9ac7feecb5fdf58725272480f/screenshots/darkmode.png
--------------------------------------------------------------------------------
/screenshots/lightmode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeMonks/NYTimes-App/f74e3820d68e29f9ac7feecb5fdf58725272480f/screenshots/lightmode.png
--------------------------------------------------------------------------------
/screenshots/nytimes_card.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeMonks/NYTimes-App/f74e3820d68e29f9ac7feecb5fdf58725272480f/screenshots/nytimes_card.jpg
--------------------------------------------------------------------------------
/screenshots/techbytes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeMonks/NYTimes-App/f74e3820d68e29f9ac7feecb5fdf58725272480f/screenshots/techbytes.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = "Topten"
2 | include ':app'
3 |
--------------------------------------------------------------------------------