commit 6b23bf1daa838a419e8a187a41be240fb1e9c3b6 Author: mehul4795 Date: Sat Mar 27 10:55:34 2021 +0530 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..603b140 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..61a9130 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..dc73612 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,22 @@ + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..e34606c --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..d5d35ec --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..c996390 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,141 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-kapt' +apply plugin: 'androidx.navigation.safeargs.kotlin' +apply plugin: 'com.google.gms.google-services' + +android { + compileSdkVersion COMPILE_SDK_VERSION + + defaultConfig { + applicationId "aculix.channelify.app" + minSdkVersion 21 + targetSdkVersion TARGET_SDK_VERSION + versionCode 7 + versionName "1.32" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + debug { + resValue "string", "youtube_api_key", YT_API_KEY + } + + release { + minifyEnabled true + shrinkResources true + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + + resValue "string", "youtube_api_key", YT_API_KEY + } + } + + kotlinOptions { + jvmTarget = "1.8" + } + + viewBinding { + enabled = true + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + packagingOptions { + exclude 'META-INF/core_release.kotlin_module' + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + // Kotlin + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" + + // Kotlin Coroutines + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$coroutinesVersion" + + // Koin + implementation "org.koin:koin-android:$koinVersion" + implementation "org.koin:koin-androidx-viewmodel:$koinVersion" + + // AndroidX + implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' + implementation 'androidx.core:core-ktx:1.3.0-rc01' + implementation "androidx.constraintlayout:constraintlayout:$clVersion" + implementation "androidx.recyclerview:recyclerview:1.1.0" + + // Architecture Components + implementation "androidx.lifecycle:lifecycle-extensions:$archVersion" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$archVersion" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:$archVersion" + implementation "androidx.lifecycle:lifecycle-runtime-ktx:$archVersion" + + // Room + implementation "androidx.room:room-runtime:$roomVersion" + implementation "androidx.room:room-ktx:$roomVersion" + kapt "androidx.room:room-compiler:$roomVersion" + + // Material theme + implementation "com.google.android.material:material:$materialThemeVersion" + + // Navigation + implementation "androidx.navigation:navigation-fragment-ktx:$navVersion" + implementation "androidx.navigation:navigation-ui-ktx:$navVersion" + + // Retrofit, OkHttp & Gson + implementation "com.squareup.retrofit2:retrofit:2.8.1" + implementation 'com.squareup.retrofit2:converter-gson:2.8.1' + implementation 'com.squareup.okhttp3:logging-interceptor:4.2.2' + + // Timber + implementation "com.jakewharton.timber:timber:$timberVersion" + + // Fast Adapter + implementation "com.mikepenz:fastadapter:$fastAdapterVersion" + implementation "com.mikepenz:fastadapter-extensions-diff:$fastAdapterVersion" + implementation "com.mikepenz:fastadapter-extensions-utils:$fastAdapterVersion" + implementation "com.mikepenz:fastadapter-extensions-ui:$fastAdapterVersion" + implementation "com.mikepenz:fastadapter-extensions-paged:$fastAdapterVersion" + implementation "com.mikepenz:itemanimators:1.1.0" + + // Coil + implementation "io.coil-kt:coil:0.10.0" + + // Paging + implementation "androidx.paging:paging-runtime:2.1.2" + + // TimeAgo + implementation 'com.github.marlonlom:timeago:4.0.1' + + // YouTube Player + implementation 'com.pierfrancescosoffritti.androidyoutubeplayer:core:10.0.5' + + // Circle ImageView + implementation 'de.hdodenhof:circleimageview:3.1.0' + + // Material Dialog + implementation "com.afollestad.material-dialogs:core:$materialDialogVersion" + implementation "com.afollestad.material-dialogs:bottomsheets:$materialDialogVersion" + + // Kotpref + implementation 'com.chibatching.kotpref:kotpref:2.10.0' + + // Firebase + implementation 'com.google.firebase:firebase-analytics:17.4.0' + implementation 'com.google.firebase:firebase-messaging:20.1.6' + implementation 'com.google.android.gms:play-services-ads:19.1.0' + + // Custom Tabs + implementation "saschpe.android:customtabs:$saschpeCustomTabs" + implementation "androidx.browser:browser:$browserVersion" + + // Modules + implementation project(':core') +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..25f7b25 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,56 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +##-------------------------- Model classes -------------------------- +-keep class aculix.channelify.app.model.** { *; } + + +#-------------------------- Coroutines --------------------------# + +# ServiceLoader support +-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {} +-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {} +-keepnames class kotlinx.coroutines.android.AndroidExceptionPreHandler {} +-keepnames class kotlinx.coroutines.android.AndroidDispatcherFactory {} + +# Most of volatile fields are updated with AFU and should not be mangled +-keepclassmembernames class kotlinx.** { + volatile ; +} + + +#-------------------------- OkHttp --------------------------# + +# JSR 305 annotations are for embedding nullability information. +-dontwarn javax.annotation.** + +# A resource is loaded with a relative path so the package of this class must be preserved. +-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase + +# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java. +-dontwarn org.codehaus.mojo.animal_sniffer.* + +# OkHttp platform used only on JVM and when Conscrypt dependency is available. +-dontwarn okhttp3.internal.platform.ConscryptPlatform + +# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java. +-dontwarn org.codehaus.mojo.animal_sniffer.* diff --git a/app/release/output.json b/app/release/output.json new file mode 100644 index 0000000..0194400 --- /dev/null +++ b/app/release/output.json @@ -0,0 +1 @@ +[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":7,"versionName":"1.32","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release","dirName":""},"path":"app-release.apk","properties":{}}] \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..e71c9e9 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/ic_launcher-web.png b/app/src/main/ic_launcher-web.png new file mode 100644 index 0000000..9e18823 Binary files /dev/null and b/app/src/main/ic_launcher-web.png differ diff --git a/app/src/main/java/aculix/channelify/app/Channelify.kt b/app/src/main/java/aculix/channelify/app/Channelify.kt new file mode 100644 index 0000000..77a3224 --- /dev/null +++ b/app/src/main/java/aculix/channelify/app/Channelify.kt @@ -0,0 +1,89 @@ +package aculix.channelify.app + +import aculix.channelify.app.di.* +import aculix.channelify.app.sharedpref.AppPref +import android.app.Application +import androidx.appcompat.app.AppCompatDelegate +import com.chibatching.kotpref.Kotpref +import com.google.android.gms.ads.MobileAds +import com.google.android.gms.ads.RequestConfiguration +import org.koin.android.ext.koin.androidContext +import org.koin.android.ext.koin.androidLogger +import org.koin.core.context.startKoin +import saschpe.android.customtabs.CustomTabsActivityLifecycleCallbacks +import timber.log.Timber +import java.util.* + +class Channelify : Application() { + + companion object { + var isAdEnabled = true + } + + override fun onCreate() { + super.onCreate() + isAdEnabled = resources.getBoolean(R.bool.enable_ads) + + initializeKotpref() + setThemeMode() + initializeTimber() + initializeKoin() + initializeCustomTabs() + + if (resources.getBoolean(R.bool.enable_ads)) initializeAdmob() + } + + private fun setThemeMode() { + if (AppPref.isLightThemeEnabled) { + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) + } else { + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) + } + + } + + private fun initializeTimber() { + if (BuildConfig.DEBUG) { + Timber.plant(Timber.DebugTree()) + } + } + + private fun initializeKotpref() { + Kotpref.init(this) + } + + private fun initializeKoin() { + startKoin { + androidLogger() + androidContext(this@Channelify) + modules( + listOf( + appModule, + homeModule, + videoPlayerModule, + commentsModule, + videoDetailsModule, + commentRepliesModule, + playlistsModule, + playlistVideosModule, + favoritesModule, + searchModule, + aboutModule + ) + ) + } + } + + private fun initializeAdmob() { + MobileAds.initialize(this) { + val testDeviceIds = listOf("7BD04413716C0B3DD5C73F814E02D21A") + val configuration = + RequestConfiguration.Builder().setTestDeviceIds(testDeviceIds).build() + MobileAds.setRequestConfiguration(configuration) + } + } + + private fun initializeCustomTabs() { + registerActivityLifecycleCallbacks(CustomTabsActivityLifecycleCallbacks()) + } +} \ No newline at end of file diff --git a/app/src/main/java/aculix/channelify/app/activity/MainActivity.kt b/app/src/main/java/aculix/channelify/app/activity/MainActivity.kt new file mode 100644 index 0000000..71e1b3e --- /dev/null +++ b/app/src/main/java/aculix/channelify/app/activity/MainActivity.kt @@ -0,0 +1,61 @@ +package aculix.channelify.app.activity + +import aculix.channelify.app.Channelify +import aculix.channelify.app.R +import aculix.channelify.app.utils.getAdaptiveBannerAdSize +import aculix.core.extensions.makeGone +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.util.DisplayMetrics +import androidx.navigation.findNavController +import androidx.navigation.ui.setupWithNavController +import com.google.android.gms.ads.* +import kotlinx.android.synthetic.main.activity_main.* +import java.util.* + +class MainActivity : AppCompatActivity() { + + private lateinit var adView: AdView + private var initialLayoutComplete = false + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + + + val navController = findNavController(R.id.navHostFragment) + bottomNavView.setupWithNavController(navController) + + if (Channelify.isAdEnabled) setupAd() else adViewContainerMain.makeGone() + + } + + override fun onPause() { + if (Channelify.isAdEnabled) adView.pause() + super.onPause() + } + + override fun onResume() { + if (Channelify.isAdEnabled) adView.resume() + super.onResume() + } + + override fun onDestroy() { + if (Channelify.isAdEnabled) adView.destroy() + super.onDestroy() + } + + private fun setupAd() { + adView = AdView(this) + adViewContainerMain.addView(adView) + adViewContainerMain.viewTreeObserver.addOnGlobalLayoutListener { + if (!initialLayoutComplete) { + initialLayoutComplete = true + + adView.adUnitId = getString(R.string.main_banner_ad_id) + adView.adSize = getAdaptiveBannerAdSize(adViewContainerMain) + adView.loadAd(AdRequest.Builder().build()) + } + } + } +} diff --git a/app/src/main/java/aculix/channelify/app/activity/SplashActivity.kt b/app/src/main/java/aculix/channelify/app/activity/SplashActivity.kt new file mode 100644 index 0000000..bb3f9b1 --- /dev/null +++ b/app/src/main/java/aculix/channelify/app/activity/SplashActivity.kt @@ -0,0 +1,16 @@ +package aculix.channelify.app.activity + +import android.content.Intent +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle + +class SplashActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val intent = Intent(this, MainActivity::class.java) + startActivity(intent) + finish() + } +} diff --git a/app/src/main/java/aculix/channelify/app/activity/VideoPlayerActivity.kt b/app/src/main/java/aculix/channelify/app/activity/VideoPlayerActivity.kt new file mode 100644 index 0000000..ca2a78e --- /dev/null +++ b/app/src/main/java/aculix/channelify/app/activity/VideoPlayerActivity.kt @@ -0,0 +1,132 @@ +package aculix.channelify.app.activity + +import aculix.channelify.app.R +import aculix.channelify.app.fragment.VideoDetailsFragment +import aculix.channelify.app.utils.FullScreenHelper +import aculix.channelify.app.viewmodel.VideoPlayerViewModel +import aculix.core.extensions.toast +import android.annotation.SuppressLint +import android.app.PictureInPictureParams +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.pm.ActivityInfo +import android.content.pm.PackageManager +import android.content.res.Configuration +import android.os.Build +import android.os.Bundle +import android.util.Rational +import android.view.ContextThemeWrapper +import android.view.View +import androidx.annotation.RequiresApi +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.AppCompatImageView +import androidx.appcompat.widget.AppCompatToggleButton +import androidx.core.content.ContextCompat +import androidx.core.os.bundleOf +import androidx.navigation.findNavController +import com.google.android.gms.ads.AdListener +import com.google.android.gms.ads.AdRequest +import com.google.android.gms.ads.InterstitialAd +import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer +import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.AbstractYouTubePlayerListener +import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.YouTubePlayerFullScreenListener +import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.utils.loadOrCueVideo +import kotlinx.android.synthetic.main.activity_video_player.* +import org.koin.androidx.viewmodel.ext.android.viewModel + + +class VideoPlayerActivity : AppCompatActivity(R.layout.activity_video_player) { + + companion object { + const val VIDEO_ID = "video_id" + + fun startActivity(context: Context?, videoId: String) { + val intent = Intent(context, VideoPlayerActivity::class.java).apply { + putExtra(VIDEO_ID, videoId) + } + context?.startActivity(intent) + } + } + + private val viewModel by viewModel() // Lazy inject ViewModel + + lateinit var fullScreenHelper: FullScreenHelper + lateinit var videoId: String + private var videoElapsedTimeInSeconds = 0f + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + fullScreenHelper = FullScreenHelper(this) + videoId = intent.getStringExtra(VIDEO_ID)!! + + // Passing the videoId as argument to the start destination + findNavController(R.id.navHostVideoPlayer).setGraph( + R.navigation.video_player_graph, + bundleOf(VideoDetailsFragment.VIDEO_ID to videoId) + ) + + initYouTubePlayer() + } + + override fun onBackPressed() { + if (ytVideoPlayerView.isFullScreen()) ytVideoPlayerView.exitFullScreen() else super.onBackPressed() + } + + private fun initYouTubePlayer() { + lifecycle.addObserver(ytVideoPlayerView) + + ytVideoPlayerView.addYouTubePlayerListener(object : AbstractYouTubePlayerListener() { + override fun onReady(youTubePlayer: YouTubePlayer) { + youTubePlayer.loadOrCueVideo(lifecycle, videoId, 0f) + addFullScreenListenerToPlayer() + setupCustomActions(youTubePlayer) + } + + override fun onCurrentSecond(youTubePlayer: YouTubePlayer, second: Float) { + videoElapsedTimeInSeconds = second + } + }) + + + } + + /** + * Adds the forward and rewind action button to the Player + */ + private fun setupCustomActions(youTubePlayer: YouTubePlayer) { + ytVideoPlayerView.getPlayerUiController() + .setCustomAction1( + ContextCompat.getDrawable(this, R.drawable.ic_rewind)!!, + View.OnClickListener { + videoElapsedTimeInSeconds -= 10 + youTubePlayer.seekTo(videoElapsedTimeInSeconds) + }) + .setCustomAction2( + ContextCompat.getDrawable(this, R.drawable.ic_forward)!!, + View.OnClickListener { + videoElapsedTimeInSeconds += 10 + youTubePlayer.seekTo(videoElapsedTimeInSeconds) + }) + } + + /** + * Changes the orientation of the activity based on the + * change of the player state (Full screen or not) + */ + @SuppressLint("SourceLockedOrientationActivity") + private fun addFullScreenListenerToPlayer() { + ytVideoPlayerView.addFullScreenListener(object : YouTubePlayerFullScreenListener { + override fun onYouTubePlayerEnterFullScreen() { + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + fullScreenHelper.enterFullScreen() + } + + override fun onYouTubePlayerExitFullScreen() { + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT + fullScreenHelper.exitFullScreen() + } + }) + } +} diff --git a/app/src/main/java/aculix/channelify/app/api/ChannelInfoService.kt b/app/src/main/java/aculix/channelify/app/api/ChannelInfoService.kt new file mode 100644 index 0000000..0db8337 --- /dev/null +++ b/app/src/main/java/aculix/channelify/app/api/ChannelInfoService.kt @@ -0,0 +1,17 @@ +package aculix.channelify.app.api + +import aculix.channelify.app.model.ChannelInfo +import retrofit2.Response +import retrofit2.http.GET +import retrofit2.http.Query + +interface ChannelInfoService { + + @GET("channels") + suspend fun getChannelInfo( + @Query("id") channelId: String, + @Query("part") part: String = "snippet, statistics, brandingSettings", + @Query("fields") fields: String = "items(snippet(title, description, publishedAt, thumbnails), statistics(viewCount, subscriberCount, videoCount), brandingSettings(image(bannerMobileHdImageUrl, bannerMobileMediumHdImageUrl)))", + @Query("maxResults") maxResults: Int = 1 + ): Response +} \ No newline at end of file diff --git a/app/src/main/java/aculix/channelify/app/api/ChannelsService.kt b/app/src/main/java/aculix/channelify/app/api/ChannelsService.kt new file mode 100644 index 0000000..68a7ba7 --- /dev/null +++ b/app/src/main/java/aculix/channelify/app/api/ChannelsService.kt @@ -0,0 +1,16 @@ +package aculix.channelify.app.api + +import aculix.channelify.app.model.ChannelUploadsPlaylistInfo +import aculix.channelify.app.model.SearchedVideo +import retrofit2.Response +import retrofit2.http.GET +import retrofit2.http.Query + +interface ChannelsService { + + @GET("channels") + suspend fun getChannelUploadsPlaylistInfo( + @Query("id") channelId: String, + @Query("part") part: String = "contentDetails" + ): Response +} \ No newline at end of file diff --git a/app/src/main/java/aculix/channelify/app/api/CommentRepliesService.kt b/app/src/main/java/aculix/channelify/app/api/CommentRepliesService.kt new file mode 100644 index 0000000..e7cfae6 --- /dev/null +++ b/app/src/main/java/aculix/channelify/app/api/CommentRepliesService.kt @@ -0,0 +1,22 @@ +package aculix.channelify.app.api + +import aculix.channelify.app.model.CommentReply +import aculix.channelify.app.utils.Constants +import retrofit2.Response +import retrofit2.http.GET +import retrofit2.http.Query + +interface CommentRepliesService { + + /** + * Gets the list of replies for a particular comment + */ + @GET("comments") + suspend fun getCommentReplies( + @Query("parentId") commentId: String, + @Query("pageToken") pageToken: String?, + @Query("part") part: String = "snippet", + @Query("fields") fields: String = "nextPageToken, items(snippet(authorDisplayName, authorProfileImageUrl, textOriginal, likeCount, publishedAt, updatedAt))", + @Query("maxResults") maxResults: Int = Constants.YT_API_MAX_RESULTS + ): Response +} \ No newline at end of file diff --git a/app/src/main/java/aculix/channelify/app/api/CommentService.kt b/app/src/main/java/aculix/channelify/app/api/CommentService.kt new file mode 100644 index 0000000..c774487 --- /dev/null +++ b/app/src/main/java/aculix/channelify/app/api/CommentService.kt @@ -0,0 +1,25 @@ +package aculix.channelify.app.api + +import aculix.channelify.app.model.Comment +import aculix.channelify.app.model.CommentReply +import aculix.channelify.app.model.PlaylistItemInfo +import aculix.channelify.app.utils.Constants +import retrofit2.Response +import retrofit2.http.GET +import retrofit2.http.Query + +interface CommentService { + + /** + * Gets the list of comments of a particular video + */ + @GET("commentThreads") + suspend fun getVideoComments( + @Query("videoId") videoId: String, + @Query("pageToken") pageToken: String?, + @Query("order") sortOrder: String, + @Query("part") part: String = "snippet", + @Query("fields") fields: String = "nextPageToken, items(snippet(topLevelComment(id, snippet(authorDisplayName, authorProfileImageUrl, textOriginal, likeCount, publishedAt, updatedAt)), totalReplyCount))", + @Query("maxResults") maxResults: Int = Constants.YT_API_MAX_RESULTS + ): Response +} \ No newline at end of file diff --git a/app/src/main/java/aculix/channelify/app/api/PlaylistItemsService.kt b/app/src/main/java/aculix/channelify/app/api/PlaylistItemsService.kt new file mode 100644 index 0000000..d6aa130 --- /dev/null +++ b/app/src/main/java/aculix/channelify/app/api/PlaylistItemsService.kt @@ -0,0 +1,20 @@ +package aculix.channelify.app.api + +import aculix.channelify.app.model.ChannelUploadsPlaylistInfo +import aculix.channelify.app.model.PlaylistItemInfo +import aculix.channelify.app.utils.Constants +import retrofit2.Response +import retrofit2.http.GET +import retrofit2.http.Query + +interface PlaylistItemsService { + + @GET("playlistItems") + suspend fun getPlaylistVideos( + @Query("playlistId") playlistId: String, + @Query("pageToken") pageToken: String?, + @Query("part") part: String = "snippet,contentDetails", + @Query("fields") fields: String = "nextPageToken, prevPageToken, items(snippet(title, thumbnails), contentDetails(videoId, videoPublishedAt))", + @Query("maxResults") maxResults: Int = Constants.YT_API_MAX_RESULTS + ): Response +} \ No newline at end of file diff --git a/app/src/main/java/aculix/channelify/app/api/PlaylistsService.kt b/app/src/main/java/aculix/channelify/app/api/PlaylistsService.kt new file mode 100644 index 0000000..d9b4da1 --- /dev/null +++ b/app/src/main/java/aculix/channelify/app/api/PlaylistsService.kt @@ -0,0 +1,19 @@ +package aculix.channelify.app.api + +import aculix.channelify.app.model.Playlist +import aculix.channelify.app.utils.Constants +import retrofit2.Response +import retrofit2.http.GET +import retrofit2.http.Query + +interface PlaylistsService { + + @GET("playlists") + suspend fun getPlaylists( + @Query("channelId") channelId: String, + @Query("pageToken") pageToken: String?, + @Query("part") part: String = "snippet,contentDetails", + @Query("fields") fields: String = "nextPageToken, items(id, snippet(publishedAt, title, description, thumbnails), contentDetails)", + @Query("maxResults") maxResults: Int = Constants.YT_API_MAX_RESULTS + ): Response +} \ No newline at end of file diff --git a/app/src/main/java/aculix/channelify/app/api/SearchVideoService.kt b/app/src/main/java/aculix/channelify/app/api/SearchVideoService.kt new file mode 100644 index 0000000..8db928a --- /dev/null +++ b/app/src/main/java/aculix/channelify/app/api/SearchVideoService.kt @@ -0,0 +1,20 @@ +package aculix.channelify.app.api + +import aculix.channelify.app.model.SearchedVideo +import aculix.channelify.app.utils.Constants +import retrofit2.Response +import retrofit2.http.GET +import retrofit2.http.Query +import retrofit2.http.QueryMap + +interface SearchVideoService { + + @GET("search") + suspend fun searchVideos( + @Query("q") searchQuery: String, + @Query("channelId") channelId: String, + @Query("pageToken") pageToken: String?, + @QueryMap defaultQueryMap: HashMap, + @Query("maxResults") maxResults: Int = Constants.YT_API_MAX_RESULTS + ): Response +} \ No newline at end of file diff --git a/app/src/main/java/aculix/channelify/app/api/VideosService.kt b/app/src/main/java/aculix/channelify/app/api/VideosService.kt new file mode 100644 index 0000000..e146a24 --- /dev/null +++ b/app/src/main/java/aculix/channelify/app/api/VideosService.kt @@ -0,0 +1,17 @@ +package aculix.channelify.app.api + +import aculix.channelify.app.model.Video +import retrofit2.Response +import retrofit2.http.GET +import retrofit2.http.Query + +interface VideosService { + + @GET("videos") + suspend fun getVideoInfo( + @Query("id") videoId: String, + @Query("part") part: String = "snippet, statistics", + @Query("fields") fields: String = "items(snippet(publishedAt, title, description, thumbnails), statistics)", + @Query("maxResults") maxResults: Int = 1 + ): Response