Merge pull request #3511 from wb9688/ktlint

Ktlint
This commit is contained in:
wb9688 2020-05-04 15:13:07 +02:00 committed by GitHub
commit b630f269c4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
58 changed files with 402 additions and 290 deletions

View file

@ -116,25 +116,40 @@ task runCheckstyle(type: Checkstyle) {
} }
} }
tasks.withType(Checkstyle).each { runCheckstyle.doLast {
checkstyleTask -> checkstyleTask.doLast { reports.all { report ->
reports.all { report -> def outputFile = report.destination
def outputFile = report.destination if (outputFile.exists() && outputFile.text.contains("severity=\"error\"")) {
if (outputFile.exists() && outputFile.text.contains("severity=\"error\"")) { throw new GradleException("There were checkstyle errors! For more info check $outputFile")
throw new GradleException("There were checkstyle errors! For more info check $outputFile")
}
} }
} }
} }
configurations {
ktlint
}
task runKtlint(type: JavaExec) {
main = "com.pinterest.ktlint.Main"
classpath = configurations.ktlint
args "src/**/*.kt"
}
task formatKtlint(type: JavaExec) {
main = "com.pinterest.ktlint.Main"
classpath = configurations.ktlint
args "-F", "src/**/*.kt"
}
afterEvaluate { afterEvaluate {
preDebugBuild.dependsOn runCheckstyle preDebugBuild.dependsOn runCheckstyle, runKtlint
} }
dependencies { dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
debugImplementation "com.puppycrawl.tools:checkstyle:${checkstyleVersion}" debugImplementation "com.puppycrawl.tools:checkstyle:${checkstyleVersion}"
ktlint "com.pinterest:ktlint:0.35.0"
androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation "android.arch.persistence.room:testing:1.1.1" androidTestImplementation "android.arch.persistence.room:testing:1.1.1"

View file

@ -116,4 +116,4 @@ class AppDatabaseTest {
testHelper.closeWhenFinished(database) testHelper.closeWhenFinished(database)
return database return database
} }
} }

View file

@ -43,15 +43,15 @@ import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue; import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
import org.schabi.newpipe.player.playqueue.SinglePlayQueue; import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.AndroidTvUtils;
import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.AndroidTvUtils;
import org.schabi.newpipe.util.ListHelper; import org.schabi.newpipe.util.ListHelper;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.PermissionHelper; import org.schabi.newpipe.util.PermissionHelper;
import org.schabi.newpipe.util.ThemeHelper; import org.schabi.newpipe.util.ThemeHelper;
import org.schabi.newpipe.views.FocusOverlayView;
import org.schabi.newpipe.util.urlfinder.UrlFinder; import org.schabi.newpipe.util.urlfinder.UrlFinder;
import org.schabi.newpipe.views.FocusOverlayView;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;

View file

@ -1,12 +1,17 @@
package org.schabi.newpipe.database.feed.dao package org.schabi.newpipe.database.feed.dao
import androidx.room.* import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Update
import io.reactivex.Flowable import io.reactivex.Flowable
import java.util.Date
import org.schabi.newpipe.database.feed.model.FeedEntity import org.schabi.newpipe.database.feed.model.FeedEntity
import org.schabi.newpipe.database.feed.model.FeedLastUpdatedEntity import org.schabi.newpipe.database.feed.model.FeedLastUpdatedEntity
import org.schabi.newpipe.database.stream.model.StreamEntity import org.schabi.newpipe.database.stream.model.StreamEntity
import org.schabi.newpipe.database.subscription.SubscriptionEntity import org.schabi.newpipe.database.subscription.SubscriptionEntity
import java.util.*
@Dao @Dao
abstract class FeedDAO { abstract class FeedDAO {

View file

@ -1,6 +1,11 @@
package org.schabi.newpipe.database.feed.dao package org.schabi.newpipe.database.feed.dao
import androidx.room.* import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Update
import io.reactivex.Flowable import io.reactivex.Flowable
import io.reactivex.Maybe import io.reactivex.Maybe
import org.schabi.newpipe.database.feed.model.FeedGroupEntity import org.schabi.newpipe.database.feed.model.FeedGroupEntity

View file

@ -27,11 +27,11 @@ import org.schabi.newpipe.database.subscription.SubscriptionEntity
] ]
) )
data class FeedEntity( data class FeedEntity(
@ColumnInfo(name = STREAM_ID) @ColumnInfo(name = STREAM_ID)
var streamId: Long, var streamId: Long,
@ColumnInfo(name = SUBSCRIPTION_ID) @ColumnInfo(name = SUBSCRIPTION_ID)
var subscriptionId: Long var subscriptionId: Long
) { ) {
companion object { companion object {
@ -40,4 +40,4 @@ data class FeedEntity(
const val STREAM_ID = "stream_id" const val STREAM_ID = "stream_id"
const val SUBSCRIPTION_ID = "subscription_id" const val SUBSCRIPTION_ID = "subscription_id"
} }
} }

View file

@ -13,18 +13,18 @@ import org.schabi.newpipe.local.subscription.FeedGroupIcon
indices = [Index(SORT_ORDER)] indices = [Index(SORT_ORDER)]
) )
data class FeedGroupEntity( data class FeedGroupEntity(
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
@ColumnInfo(name = ID) @ColumnInfo(name = ID)
val uid: Long, val uid: Long,
@ColumnInfo(name = NAME) @ColumnInfo(name = NAME)
var name: String, var name: String,
@ColumnInfo(name = ICON) @ColumnInfo(name = ICON)
var icon: FeedGroupIcon, var icon: FeedGroupIcon,
@ColumnInfo(name = SORT_ORDER) @ColumnInfo(name = SORT_ORDER)
var sortOrder: Long = -1 var sortOrder: Long = -1
) { ) {
companion object { companion object {
const val FEED_GROUP_TABLE = "feed_group" const val FEED_GROUP_TABLE = "feed_group"
@ -36,4 +36,4 @@ data class FeedGroupEntity(
const val GROUP_ALL_ID = -1L const val GROUP_ALL_ID = -1L
} }
} }

View file

@ -29,11 +29,11 @@ import org.schabi.newpipe.database.subscription.SubscriptionEntity
] ]
) )
data class FeedGroupSubscriptionEntity( data class FeedGroupSubscriptionEntity(
@ColumnInfo(name = GROUP_ID) @ColumnInfo(name = GROUP_ID)
var feedGroupId: Long, var feedGroupId: Long,
@ColumnInfo(name = SUBSCRIPTION_ID) @ColumnInfo(name = SUBSCRIPTION_ID)
var subscriptionId: Long var subscriptionId: Long
) { ) {
companion object { companion object {
@ -42,4 +42,4 @@ data class FeedGroupSubscriptionEntity(
const val GROUP_ID = "group_id" const val GROUP_ID = "group_id"
const val SUBSCRIPTION_ID = "subscription_id" const val SUBSCRIPTION_ID = "subscription_id"
} }
} }

View file

@ -4,10 +4,10 @@ import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.ForeignKey import androidx.room.ForeignKey
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import java.util.Date
import org.schabi.newpipe.database.feed.model.FeedLastUpdatedEntity.Companion.FEED_LAST_UPDATED_TABLE import org.schabi.newpipe.database.feed.model.FeedLastUpdatedEntity.Companion.FEED_LAST_UPDATED_TABLE
import org.schabi.newpipe.database.feed.model.FeedLastUpdatedEntity.Companion.SUBSCRIPTION_ID import org.schabi.newpipe.database.feed.model.FeedLastUpdatedEntity.Companion.SUBSCRIPTION_ID
import org.schabi.newpipe.database.subscription.SubscriptionEntity import org.schabi.newpipe.database.subscription.SubscriptionEntity
import java.util.*
@Entity( @Entity(
tableName = FEED_LAST_UPDATED_TABLE, tableName = FEED_LAST_UPDATED_TABLE,
@ -20,12 +20,12 @@ import java.util.*
] ]
) )
data class FeedLastUpdatedEntity( data class FeedLastUpdatedEntity(
@PrimaryKey @PrimaryKey
@ColumnInfo(name = SUBSCRIPTION_ID) @ColumnInfo(name = SUBSCRIPTION_ID)
var subscriptionId: Long, var subscriptionId: Long,
@ColumnInfo(name = LAST_UPDATED) @ColumnInfo(name = LAST_UPDATED)
var lastUpdated: Date? = null var lastUpdated: Date? = null
) { ) {
companion object { companion object {
@ -34,4 +34,4 @@ data class FeedLastUpdatedEntity(
const val SUBSCRIPTION_ID = "subscription_id" const val SUBSCRIPTION_ID = "subscription_id"
const val LAST_UPDATED = "last_updated" const val LAST_UPDATED = "last_updated"
} }
} }

View file

@ -2,21 +2,21 @@ package org.schabi.newpipe.database.history.model
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Embedded import androidx.room.Embedded
import java.util.Date
import org.schabi.newpipe.database.stream.model.StreamEntity import org.schabi.newpipe.database.stream.model.StreamEntity
import java.util.*
data class StreamHistoryEntry( data class StreamHistoryEntry(
@Embedded @Embedded
val streamEntity: StreamEntity, val streamEntity: StreamEntity,
@ColumnInfo(name = StreamHistoryEntity.JOIN_STREAM_ID) @ColumnInfo(name = StreamHistoryEntity.JOIN_STREAM_ID)
val streamId: Long, val streamId: Long,
@ColumnInfo(name = StreamHistoryEntity.STREAM_ACCESS_DATE) @ColumnInfo(name = StreamHistoryEntity.STREAM_ACCESS_DATE)
val accessDate: Date, val accessDate: Date,
@ColumnInfo(name = StreamHistoryEntity.STREAM_REPEAT_COUNT) @ColumnInfo(name = StreamHistoryEntity.STREAM_REPEAT_COUNT)
val repeatCount: Long val repeatCount: Long
) { ) {
fun toStreamHistoryEntity(): StreamHistoryEntity { fun toStreamHistoryEntity(): StreamHistoryEntity {

View file

@ -8,14 +8,14 @@ import org.schabi.newpipe.database.stream.model.StreamEntity
import org.schabi.newpipe.extractor.stream.StreamInfoItem import org.schabi.newpipe.extractor.stream.StreamInfoItem
class PlaylistStreamEntry( class PlaylistStreamEntry(
@Embedded @Embedded
val streamEntity: StreamEntity, val streamEntity: StreamEntity,
@ColumnInfo(name = PlaylistStreamEntity.JOIN_STREAM_ID) @ColumnInfo(name = PlaylistStreamEntity.JOIN_STREAM_ID)
val streamId: Long, val streamId: Long,
@ColumnInfo(name = PlaylistStreamEntity.JOIN_INDEX) @ColumnInfo(name = PlaylistStreamEntity.JOIN_INDEX)
val joinIndex: Int val joinIndex: Int
) : LocalItem { ) : LocalItem {
@Throws(IllegalArgumentException::class) @Throws(IllegalArgumentException::class)

View file

@ -2,24 +2,24 @@ package org.schabi.newpipe.database.stream
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Embedded import androidx.room.Embedded
import java.util.Date
import org.schabi.newpipe.database.LocalItem import org.schabi.newpipe.database.LocalItem
import org.schabi.newpipe.database.history.model.StreamHistoryEntity import org.schabi.newpipe.database.history.model.StreamHistoryEntity
import org.schabi.newpipe.database.stream.model.StreamEntity import org.schabi.newpipe.database.stream.model.StreamEntity
import org.schabi.newpipe.extractor.stream.StreamInfoItem import org.schabi.newpipe.extractor.stream.StreamInfoItem
import java.util.*
class StreamStatisticsEntry( class StreamStatisticsEntry(
@Embedded @Embedded
val streamEntity: StreamEntity, val streamEntity: StreamEntity,
@ColumnInfo(name = StreamHistoryEntity.JOIN_STREAM_ID) @ColumnInfo(name = StreamHistoryEntity.JOIN_STREAM_ID)
val streamId: Long, val streamId: Long,
@ColumnInfo(name = STREAM_LATEST_DATE) @ColumnInfo(name = STREAM_LATEST_DATE)
val latestAccessDate: Date, val latestAccessDate: Date,
@ColumnInfo(name = STREAM_WATCH_COUNT) @ColumnInfo(name = STREAM_WATCH_COUNT)
val watchCount: Long val watchCount: Long
) : LocalItem { ) : LocalItem {
fun toStreamInfoItem(): StreamInfoItem { fun toStreamInfoItem(): StreamInfoItem {

View file

@ -1,15 +1,19 @@
package org.schabi.newpipe.database.stream.dao package org.schabi.newpipe.database.stream.dao
import androidx.room.* import androidx.room.ColumnInfo
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import io.reactivex.Flowable import io.reactivex.Flowable
import java.util.Date
import org.schabi.newpipe.database.BasicDAO import org.schabi.newpipe.database.BasicDAO
import org.schabi.newpipe.database.stream.model.StreamEntity import org.schabi.newpipe.database.stream.model.StreamEntity
import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_ID import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_ID
import org.schabi.newpipe.extractor.stream.StreamType import org.schabi.newpipe.extractor.stream.StreamType
import org.schabi.newpipe.extractor.stream.StreamType.AUDIO_LIVE_STREAM import org.schabi.newpipe.extractor.stream.StreamType.AUDIO_LIVE_STREAM
import org.schabi.newpipe.extractor.stream.StreamType.LIVE_STREAM import org.schabi.newpipe.extractor.stream.StreamType.LIVE_STREAM
import java.util.*
import kotlin.collections.ArrayList
@Dao @Dao
abstract class StreamDAO : BasicDAO<StreamEntity> { abstract class StreamDAO : BasicDAO<StreamEntity> {
@ -94,7 +98,6 @@ abstract class StreamDAO : BasicDAO<StreamEntity> {
if (existentMinimalStream.duration > 0 && newerStream.duration < 0) { if (existentMinimalStream.duration > 0 && newerStream.duration < 0) {
newerStream.duration = existentMinimalStream.duration newerStream.duration = existentMinimalStream.duration
} }
} }
} }
@ -116,21 +119,22 @@ abstract class StreamDAO : BasicDAO<StreamEntity> {
* Minimal entry class used when comparing/updating an existent stream. * Minimal entry class used when comparing/updating an existent stream.
*/ */
internal data class StreamCompareFeed( internal data class StreamCompareFeed(
@ColumnInfo(name = STREAM_ID) @ColumnInfo(name = STREAM_ID)
var uid: Long = 0, var uid: Long = 0,
@ColumnInfo(name = StreamEntity.STREAM_TYPE) @ColumnInfo(name = StreamEntity.STREAM_TYPE)
var streamType: StreamType, var streamType: StreamType,
@ColumnInfo(name = StreamEntity.STREAM_TEXTUAL_UPLOAD_DATE) @ColumnInfo(name = StreamEntity.STREAM_TEXTUAL_UPLOAD_DATE)
var textualUploadDate: String? = null, var textualUploadDate: String? = null,
@ColumnInfo(name = StreamEntity.STREAM_UPLOAD_DATE) @ColumnInfo(name = StreamEntity.STREAM_UPLOAD_DATE)
var uploadDate: Date? = null, var uploadDate: Date? = null,
@ColumnInfo(name = StreamEntity.STREAM_IS_UPLOAD_DATE_APPROXIMATION) @ColumnInfo(name = StreamEntity.STREAM_IS_UPLOAD_DATE_APPROXIMATION)
var isUploadDateApproximation: Boolean? = null, var isUploadDateApproximation: Boolean? = null,
@ColumnInfo(name = StreamEntity.STREAM_DURATION) @ColumnInfo(name = StreamEntity.STREAM_DURATION)
var duration: Long) var duration: Long
)
} }

View file

@ -1,6 +1,13 @@
package org.schabi.newpipe.database.stream.model package org.schabi.newpipe.database.stream.model
import androidx.room.* import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.Index
import androidx.room.PrimaryKey
import java.io.Serializable
import java.util.Calendar
import java.util.Date
import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_SERVICE_ID import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_SERVICE_ID
import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_TABLE import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_TABLE
import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_URL import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_URL
@ -9,8 +16,6 @@ import org.schabi.newpipe.extractor.stream.StreamInfo
import org.schabi.newpipe.extractor.stream.StreamInfoItem import org.schabi.newpipe.extractor.stream.StreamInfoItem
import org.schabi.newpipe.extractor.stream.StreamType import org.schabi.newpipe.extractor.stream.StreamType
import org.schabi.newpipe.player.playqueue.PlayQueueItem import org.schabi.newpipe.player.playqueue.PlayQueueItem
import java.io.Serializable
import java.util.*
@Entity(tableName = STREAM_TABLE, @Entity(tableName = STREAM_TABLE,
indices = [ indices = [
@ -18,42 +23,42 @@ import java.util.*
] ]
) )
data class StreamEntity( data class StreamEntity(
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
@ColumnInfo(name = STREAM_ID) @ColumnInfo(name = STREAM_ID)
var uid: Long = 0, var uid: Long = 0,
@ColumnInfo(name = STREAM_SERVICE_ID) @ColumnInfo(name = STREAM_SERVICE_ID)
var serviceId: Int, var serviceId: Int,
@ColumnInfo(name = STREAM_URL) @ColumnInfo(name = STREAM_URL)
var url: String, var url: String,
@ColumnInfo(name = STREAM_TITLE) @ColumnInfo(name = STREAM_TITLE)
var title: String, var title: String,
@ColumnInfo(name = STREAM_TYPE) @ColumnInfo(name = STREAM_TYPE)
var streamType: StreamType, var streamType: StreamType,
@ColumnInfo(name = STREAM_DURATION) @ColumnInfo(name = STREAM_DURATION)
var duration: Long, var duration: Long,
@ColumnInfo(name = STREAM_UPLOADER) @ColumnInfo(name = STREAM_UPLOADER)
var uploader: String, var uploader: String,
@ColumnInfo(name = STREAM_THUMBNAIL_URL) @ColumnInfo(name = STREAM_THUMBNAIL_URL)
var thumbnailUrl: String? = null, var thumbnailUrl: String? = null,
@ColumnInfo(name = STREAM_VIEWS) @ColumnInfo(name = STREAM_VIEWS)
var viewCount: Long? = null, var viewCount: Long? = null,
@ColumnInfo(name = STREAM_TEXTUAL_UPLOAD_DATE) @ColumnInfo(name = STREAM_TEXTUAL_UPLOAD_DATE)
var textualUploadDate: String? = null, var textualUploadDate: String? = null,
@ColumnInfo(name = STREAM_UPLOAD_DATE) @ColumnInfo(name = STREAM_UPLOAD_DATE)
var uploadDate: Date? = null, var uploadDate: Date? = null,
@ColumnInfo(name = STREAM_IS_UPLOAD_DATE_APPROXIMATION) @ColumnInfo(name = STREAM_IS_UPLOAD_DATE_APPROXIMATION)
var isUploadDateApproximation: Boolean? = null var isUploadDateApproximation: Boolean? = null
) : Serializable { ) : Serializable {
@Ignore @Ignore

View file

@ -1,6 +1,10 @@
package org.schabi.newpipe.database.subscription package org.schabi.newpipe.database.subscription
import androidx.room.* import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import io.reactivex.Flowable import io.reactivex.Flowable
import io.reactivex.Maybe import io.reactivex.Maybe
import org.schabi.newpipe.database.BasicDAO import org.schabi.newpipe.database.BasicDAO

View file

@ -41,12 +41,12 @@ import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.search.SearchExtractor; import org.schabi.newpipe.extractor.search.SearchExtractor;
import org.schabi.newpipe.extractor.search.SearchInfo; import org.schabi.newpipe.extractor.search.SearchInfo;
import org.schabi.newpipe.util.AndroidTvUtils;
import org.schabi.newpipe.fragments.BackPressable; import org.schabi.newpipe.fragments.BackPressable;
import org.schabi.newpipe.fragments.list.BaseListFragment; import org.schabi.newpipe.fragments.list.BaseListFragment;
import org.schabi.newpipe.local.history.HistoryRecordManager; import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.AndroidTvUtils;
import org.schabi.newpipe.util.AnimationUtils; import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ExtractorHelper;

View file

@ -7,6 +7,8 @@ import io.reactivex.Flowable
import io.reactivex.Maybe import io.reactivex.Maybe
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import java.util.Calendar
import java.util.Date
import org.schabi.newpipe.MainActivity.DEBUG import org.schabi.newpipe.MainActivity.DEBUG
import org.schabi.newpipe.NewPipeDatabase import org.schabi.newpipe.NewPipeDatabase
import org.schabi.newpipe.database.feed.model.FeedEntity import org.schabi.newpipe.database.feed.model.FeedEntity
@ -16,8 +18,6 @@ import org.schabi.newpipe.database.stream.model.StreamEntity
import org.schabi.newpipe.extractor.stream.StreamInfoItem import org.schabi.newpipe.extractor.stream.StreamInfoItem
import org.schabi.newpipe.extractor.stream.StreamType import org.schabi.newpipe.extractor.stream.StreamType
import org.schabi.newpipe.local.subscription.FeedGroupIcon import org.schabi.newpipe.local.subscription.FeedGroupIcon
import java.util.*
import kotlin.collections.ArrayList
class FeedDatabaseManager(context: Context) { class FeedDatabaseManager(context: Context) {
private val database = NewPipeDatabase.getInstance(context) private val database = NewPipeDatabase.getInstance(context)
@ -70,8 +70,11 @@ class FeedDatabaseManager(context: Context) {
fun markAsOutdated(subscriptionId: Long) = feedTable fun markAsOutdated(subscriptionId: Long) = feedTable
.setLastUpdatedForSubscription(FeedLastUpdatedEntity(subscriptionId, null)) .setLastUpdatedForSubscription(FeedLastUpdatedEntity(subscriptionId, null))
fun upsertAll(subscriptionId: Long, items: List<StreamInfoItem>, fun upsertAll(
oldestAllowedDate: Date = FEED_OLDEST_ALLOWED_DATE.time) { subscriptionId: Long,
items: List<StreamInfoItem>,
oldestAllowedDate: Date = FEED_OLDEST_ALLOWED_DATE.time
) {
val itemsToInsert = ArrayList<StreamInfoItem>() val itemsToInsert = ArrayList<StreamInfoItem>()
loop@ for (streamItem in items) { loop@ for (streamItem in items) {
val uploadDate = streamItem.uploadDate val uploadDate = streamItem.uploadDate
@ -107,9 +110,9 @@ class FeedDatabaseManager(context: Context) {
if (DEBUG) Log.d(this::class.java.simpleName, "clear() → streamTable.deleteOrphans() → $deletedOrphans") if (DEBUG) Log.d(this::class.java.simpleName, "clear() → streamTable.deleteOrphans() → $deletedOrphans")
} }
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
// Feed Groups // Feed Groups
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
fun subscriptionIdsForGroup(groupId: Long): Flowable<List<Long>> { fun subscriptionIdsForGroup(groupId: Long): Flowable<List<Long>> {
return feedGroupTable.getSubscriptionIdsFor(groupId) return feedGroupTable.getSubscriptionIdsFor(groupId)
@ -161,6 +164,5 @@ class FeedDatabaseManager(context: Context) {
FeedGroupEntity.GROUP_ALL_ID -> feedTable.oldestSubscriptionUpdateFromAll() FeedGroupEntity.GROUP_ALL_ID -> feedTable.oldestSubscriptionUpdateFromAll()
else -> feedTable.oldestSubscriptionUpdate(groupId) else -> feedTable.oldestSubscriptionUpdate(groupId)
} }
} }
} }

View file

@ -22,14 +22,28 @@ package org.schabi.newpipe.local.feed
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.os.Parcelable import android.os.Parcelable
import android.view.* import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders import androidx.lifecycle.ViewModelProviders
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import icepick.State import icepick.State
import kotlinx.android.synthetic.main.error_retry.* import java.util.Calendar
import kotlinx.android.synthetic.main.fragment_feed.* import kotlinx.android.synthetic.main.error_retry.error_button_retry
import kotlinx.android.synthetic.main.error_retry.error_message_view
import kotlinx.android.synthetic.main.fragment_feed.empty_state_view
import kotlinx.android.synthetic.main.fragment_feed.error_panel
import kotlinx.android.synthetic.main.fragment_feed.items_list
import kotlinx.android.synthetic.main.fragment_feed.loading_progress_bar
import kotlinx.android.synthetic.main.fragment_feed.loading_progress_text
import kotlinx.android.synthetic.main.fragment_feed.refresh_root_view
import kotlinx.android.synthetic.main.fragment_feed.refresh_subtitle_text
import kotlinx.android.synthetic.main.fragment_feed.refresh_text
import org.schabi.newpipe.R import org.schabi.newpipe.R
import org.schabi.newpipe.database.feed.model.FeedGroupEntity import org.schabi.newpipe.database.feed.model.FeedGroupEntity
import org.schabi.newpipe.fragments.list.BaseListFragment import org.schabi.newpipe.fragments.list.BaseListFragment
@ -37,7 +51,6 @@ import org.schabi.newpipe.local.feed.service.FeedLoadService
import org.schabi.newpipe.report.UserAction import org.schabi.newpipe.report.UserAction
import org.schabi.newpipe.util.AnimationUtils.animateView import org.schabi.newpipe.util.AnimationUtils.animateView
import org.schabi.newpipe.util.Localization import org.schabi.newpipe.util.Localization
import java.util.*
class FeedFragment : BaseListFragment<FeedState, Unit>() { class FeedFragment : BaseListFragment<FeedState, Unit>() {
private lateinit var viewModel: FeedViewModel private lateinit var viewModel: FeedViewModel
@ -98,9 +111,9 @@ class FeedFragment : BaseListFragment<FeedState, Unit>() {
} }
} }
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
// Menu // Menu
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater) super.onCreateOptionsMenu(menu, inflater)
@ -150,9 +163,9 @@ class FeedFragment : BaseListFragment<FeedState, Unit>() {
activity?.supportActionBar?.subtitle = null activity?.supportActionBar?.subtitle = null
} }
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
// Handling // Handling
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
override fun showLoading() { override fun showLoading() {
animateView(refresh_root_view, false, 0) animateView(refresh_root_view, false, 0)
@ -259,7 +272,6 @@ class FeedFragment : BaseListFragment<FeedState, Unit>() {
} }
} }
private fun handleErrorState(errorState: FeedState.ErrorState): Boolean { private fun handleErrorState(errorState: FeedState.ErrorState): Boolean {
hideLoading() hideLoading()
errorState.error?.let { errorState.error?.let {
@ -283,9 +295,9 @@ class FeedFragment : BaseListFragment<FeedState, Unit>() {
refresh_text?.text = getString(R.string.feed_oldest_subscription_update, oldestSubscriptionUpdateText) refresh_text?.text = getString(R.string.feed_oldest_subscription_update, oldestSubscriptionUpdateText)
} }
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
// Load Service Handling // Load Service Handling
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
override fun doInitialLoadLogic() {} override fun doInitialLoadLogic() {}
override fun reloadContent() = triggerUpdate() override fun reloadContent() = triggerUpdate()

View file

@ -1,24 +1,24 @@
package org.schabi.newpipe.local.feed package org.schabi.newpipe.local.feed
import androidx.annotation.StringRes import androidx.annotation.StringRes
import java.util.Calendar
import org.schabi.newpipe.extractor.stream.StreamInfoItem import org.schabi.newpipe.extractor.stream.StreamInfoItem
import java.util.*
sealed class FeedState { sealed class FeedState {
data class ProgressState( data class ProgressState(
val currentProgress: Int = -1, val currentProgress: Int = -1,
val maxProgress: Int = -1, val maxProgress: Int = -1,
@StringRes val progressMessage: Int = 0 @StringRes val progressMessage: Int = 0
) : FeedState() ) : FeedState()
data class LoadedState( data class LoadedState(
val items: List<StreamInfoItem>, val items: List<StreamInfoItem>,
val oldestUpdate: Calendar? = null, val oldestUpdate: Calendar? = null,
val notLoadedCount: Long, val notLoadedCount: Long,
val itemsErrors: List<Throwable> = emptyList() val itemsErrors: List<Throwable> = emptyList()
) : FeedState() ) : FeedState()
data class ErrorState( data class ErrorState(
val error: Throwable? = null val error: Throwable? = null
) : FeedState() ) : FeedState()
} }

View file

@ -9,13 +9,17 @@ import io.reactivex.Flowable
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.Function4 import io.reactivex.functions.Function4
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import java.util.Calendar
import java.util.Date
import java.util.concurrent.TimeUnit
import org.schabi.newpipe.database.feed.model.FeedGroupEntity import org.schabi.newpipe.database.feed.model.FeedGroupEntity
import org.schabi.newpipe.extractor.stream.StreamInfoItem import org.schabi.newpipe.extractor.stream.StreamInfoItem
import org.schabi.newpipe.local.feed.service.FeedEventManager import org.schabi.newpipe.local.feed.service.FeedEventManager
import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.* import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.ErrorResultEvent
import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.IdleEvent
import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.ProgressEvent
import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.SuccessResultEvent
import org.schabi.newpipe.util.DEFAULT_THROTTLE_TIMEOUT import org.schabi.newpipe.util.DEFAULT_THROTTLE_TIMEOUT
import java.util.*
import java.util.concurrent.TimeUnit
class FeedViewModel(applicationContext: Context, val groupId: Long = FeedGroupEntity.GROUP_ALL_ID) : ViewModel() { class FeedViewModel(applicationContext: Context, val groupId: Long = FeedGroupEntity.GROUP_ALL_ID) : ViewModel() {
class Factory(val context: Context, val groupId: Long = FeedGroupEntity.GROUP_ALL_ID) : ViewModelProvider.Factory { class Factory(val context: Context, val groupId: Long = FeedGroupEntity.GROUP_ALL_ID) : ViewModelProvider.Factory {
@ -68,4 +72,4 @@ class FeedViewModel(applicationContext: Context, val groupId: Long = FeedGroupEn
} }
private data class CombineResultHolder(val t1: FeedEventManager.Event, val t2: List<StreamInfoItem>, val t3: Long, val t4: Date?) private data class CombineResultHolder(val t1: FeedEventManager.Event, val t2: List<StreamInfoItem>, val t3: Long, val t4: Date?)
} }

View file

@ -3,8 +3,8 @@ package org.schabi.newpipe.local.feed.service
import androidx.annotation.StringRes import androidx.annotation.StringRes
import io.reactivex.Flowable import io.reactivex.Flowable
import io.reactivex.processors.BehaviorProcessor import io.reactivex.processors.BehaviorProcessor
import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.IdleEvent
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.IdleEvent
object FeedEventManager { object FeedEventManager {
private var processor: BehaviorProcessor<Event> = BehaviorProcessor.create() private var processor: BehaviorProcessor<Event> = BehaviorProcessor.create()
@ -34,5 +34,4 @@ object FeedEventManager {
data class SuccessResultEvent(val itemsErrors: List<Throwable> = emptyList()) : Event() data class SuccessResultEvent(val itemsErrors: List<Throwable> = emptyList()) : Event()
data class ErrorResultEvent(val error: Throwable) : Event() data class ErrorResultEvent(val error: Throwable) : Event()
} }
} }

View file

@ -40,6 +40,11 @@ import io.reactivex.functions.Consumer
import io.reactivex.functions.Function import io.reactivex.functions.Function
import io.reactivex.processors.PublishProcessor import io.reactivex.processors.PublishProcessor
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import java.io.IOException
import java.util.Calendar
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger
import org.reactivestreams.Subscriber import org.reactivestreams.Subscriber
import org.reactivestreams.Subscription import org.reactivestreams.Subscription
import org.schabi.newpipe.MainActivity.DEBUG import org.schabi.newpipe.MainActivity.DEBUG
@ -49,17 +54,14 @@ import org.schabi.newpipe.extractor.ListInfo
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException import org.schabi.newpipe.extractor.exceptions.ReCaptchaException
import org.schabi.newpipe.extractor.stream.StreamInfoItem import org.schabi.newpipe.extractor.stream.StreamInfoItem
import org.schabi.newpipe.local.feed.FeedDatabaseManager import org.schabi.newpipe.local.feed.FeedDatabaseManager
import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.* import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.ErrorResultEvent
import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.IdleEvent
import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.ProgressEvent
import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.SuccessResultEvent
import org.schabi.newpipe.local.feed.service.FeedEventManager.postEvent import org.schabi.newpipe.local.feed.service.FeedEventManager.postEvent
import org.schabi.newpipe.local.subscription.SubscriptionManager import org.schabi.newpipe.local.subscription.SubscriptionManager
import org.schabi.newpipe.util.ExceptionUtils import org.schabi.newpipe.util.ExceptionUtils
import org.schabi.newpipe.util.ExtractorHelper import org.schabi.newpipe.util.ExtractorHelper
import java.io.IOException
import java.util.*
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger
import kotlin.collections.ArrayList
class FeedLoadService : Service() { class FeedLoadService : Service() {
companion object { companion object {
@ -94,9 +96,9 @@ class FeedLoadService : Service() {
private var disposables = CompositeDisposable() private var disposables = CompositeDisposable()
private var notificationUpdater = PublishProcessor.create<String>() private var notificationUpdater = PublishProcessor.create<String>()
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
// Lifecycle // Lifecycle
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
@ -151,9 +153,9 @@ class FeedLoadService : Service() {
return null return null
} }
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
// Loading & Handling // Loading & Handling
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
private class RequestException(val subscriptionId: Long, message: String, cause: Throwable) : Exception(message, cause) { private class RequestException(val subscriptionId: Long, message: String, cause: Throwable) : Exception(message, cause) {
companion object { companion object {
@ -312,7 +314,6 @@ class FeedLoadService : Service() {
feedResultsHolder.addErrors(RequestException.wrapList(subscriptionId, info)) feedResultsHolder.addErrors(RequestException.wrapList(subscriptionId, info))
feedDatabaseManager.markAsOutdated(subscriptionId) feedDatabaseManager.markAsOutdated(subscriptionId)
} }
} else if (notification.isOnError) { } else if (notification.isOnError) {
val error = notification.error!! val error = notification.error!!
feedResultsHolder.addError(error) feedResultsHolder.addError(error)
@ -325,7 +326,6 @@ class FeedLoadService : Service() {
} }
} }
private val errorHandlingConsumer: Consumer<Notification<Pair<Long, ListInfo<StreamInfoItem>>>> private val errorHandlingConsumer: Consumer<Notification<Pair<Long, ListInfo<StreamInfoItem>>>>
get() = Consumer { get() = Consumer {
if (it.isOnError) { if (it.isOnError) {
@ -354,9 +354,9 @@ class FeedLoadService : Service() {
broadcastProgress() broadcastProgress()
} }
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
// Notification // Notification
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
private lateinit var notificationManager: NotificationManagerCompat private lateinit var notificationManager: NotificationManagerCompat
private lateinit var notificationBuilder: NotificationCompat.Builder private lateinit var notificationBuilder: NotificationCompat.Builder
@ -412,9 +412,9 @@ class FeedLoadService : Service() {
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()) notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build())
} }
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
// Notification Actions // Notification Actions
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
private lateinit var broadcastReceiver: BroadcastReceiver private lateinit var broadcastReceiver: BroadcastReceiver
private val cancelSignal = AtomicBoolean() private val cancelSignal = AtomicBoolean()
@ -430,18 +430,18 @@ class FeedLoadService : Service() {
registerReceiver(broadcastReceiver, IntentFilter(ACTION_CANCEL)) registerReceiver(broadcastReceiver, IntentFilter(ACTION_CANCEL))
} }
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
// Error handling // Error handling
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
private fun handleError(error: Throwable) { private fun handleError(error: Throwable) {
postEvent(ErrorResultEvent(error)) postEvent(ErrorResultEvent(error))
stopService() stopService()
} }
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
// Results Holder // Results Holder
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
class ResultsHolder { class ResultsHolder {
/** /**
@ -463,4 +463,4 @@ class FeedLoadService : Service() {
itemsErrors = itemsErrorsHolder.toList() itemsErrors = itemsErrorsHolder.toList()
} }
} }
} }

View file

@ -7,15 +7,15 @@ import org.schabi.newpipe.R
import org.schabi.newpipe.util.ThemeHelper import org.schabi.newpipe.util.ThemeHelper
enum class FeedGroupIcon( enum class FeedGroupIcon(
/** /**
* The id that will be used to store and retrieve icons from some persistent storage (e.g. DB). * The id that will be used to store and retrieve icons from some persistent storage (e.g. DB).
*/ */
val id: Int, val id: Int,
/** /**
* The attribute that points to a drawable resource. "R.attr" is used here to support multiple themes. * The attribute that points to a drawable resource. "R.attr" is used here to support multiple themes.
*/ */
@AttrRes val drawableResourceAttr: Int @AttrRes val drawableResourceAttr: Int
) { ) {
ALL(0, R.attr.ic_asterisk), ALL(0, R.attr.ic_asterisk),
MUSIC(1, R.attr.ic_music_note), MUSIC(1, R.attr.ic_music_note),
@ -60,4 +60,4 @@ enum class FeedGroupIcon(
fun getDrawableRes(context: Context): Int { fun getDrawableRes(context: Context): Int {
return ThemeHelper.resolveResourceIdFromAttr(context, drawableResourceAttr) return ThemeHelper.resolveResourceIdFromAttr(context, drawableResourceAttr)
} }
} }

View file

@ -2,13 +2,21 @@ package org.schabi.newpipe.local.subscription
import android.app.Activity import android.app.Activity
import android.app.AlertDialog import android.app.AlertDialog
import android.content.* import android.content.BroadcastReceiver
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.IntentFilter
import android.content.res.Configuration import android.content.res.Configuration
import android.os.Bundle import android.os.Bundle
import android.os.Environment import android.os.Environment
import android.os.Parcelable import android.os.Parcelable
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.view.* import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.lifecycle.ViewModelProviders import androidx.lifecycle.ViewModelProviders
import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.localbroadcastmanager.content.LocalBroadcastManager
@ -21,8 +29,15 @@ import com.xwray.groupie.Section
import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder
import icepick.State import icepick.State
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.dialog_title.view.* import java.io.File
import kotlinx.android.synthetic.main.fragment_subscription.* import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import kotlin.math.floor
import kotlin.math.max
import kotlinx.android.synthetic.main.dialog_title.view.itemAdditionalDetails
import kotlinx.android.synthetic.main.dialog_title.view.itemTitleView
import kotlinx.android.synthetic.main.fragment_subscription.items_list
import org.schabi.newpipe.R import org.schabi.newpipe.R
import org.schabi.newpipe.database.feed.model.FeedGroupEntity import org.schabi.newpipe.database.feed.model.FeedGroupEntity
import org.schabi.newpipe.extractor.channel.ChannelInfoItem import org.schabi.newpipe.extractor.channel.ChannelInfoItem
@ -30,21 +45,29 @@ import org.schabi.newpipe.fragments.BaseStateFragment
import org.schabi.newpipe.local.subscription.SubscriptionViewModel.SubscriptionState import org.schabi.newpipe.local.subscription.SubscriptionViewModel.SubscriptionState
import org.schabi.newpipe.local.subscription.dialog.FeedGroupDialog import org.schabi.newpipe.local.subscription.dialog.FeedGroupDialog
import org.schabi.newpipe.local.subscription.dialog.FeedGroupReorderDialog import org.schabi.newpipe.local.subscription.dialog.FeedGroupReorderDialog
import org.schabi.newpipe.local.subscription.item.* import org.schabi.newpipe.local.subscription.item.ChannelItem
import org.schabi.newpipe.local.subscription.item.EmptyPlaceholderItem
import org.schabi.newpipe.local.subscription.item.FeedGroupAddItem
import org.schabi.newpipe.local.subscription.item.FeedGroupCardItem
import org.schabi.newpipe.local.subscription.item.FeedGroupCarouselItem
import org.schabi.newpipe.local.subscription.item.FeedImportExportItem
import org.schabi.newpipe.local.subscription.item.HeaderWithMenuItem
import org.schabi.newpipe.local.subscription.item.HeaderWithMenuItem.Companion.PAYLOAD_UPDATE_VISIBILITY_MENU_ITEM import org.schabi.newpipe.local.subscription.item.HeaderWithMenuItem.Companion.PAYLOAD_UPDATE_VISIBILITY_MENU_ITEM
import org.schabi.newpipe.local.subscription.services.SubscriptionsExportService import org.schabi.newpipe.local.subscription.services.SubscriptionsExportService
import org.schabi.newpipe.local.subscription.services.SubscriptionsExportService.EXPORT_COMPLETE_ACTION import org.schabi.newpipe.local.subscription.services.SubscriptionsExportService.EXPORT_COMPLETE_ACTION
import org.schabi.newpipe.local.subscription.services.SubscriptionsExportService.KEY_FILE_PATH import org.schabi.newpipe.local.subscription.services.SubscriptionsExportService.KEY_FILE_PATH
import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService
import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.* import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.IMPORT_COMPLETE_ACTION
import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.KEY_MODE
import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.KEY_VALUE
import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.PREVIOUS_EXPORT_MODE
import org.schabi.newpipe.report.UserAction import org.schabi.newpipe.report.UserAction
import org.schabi.newpipe.util.*
import org.schabi.newpipe.util.AnimationUtils.animateView import org.schabi.newpipe.util.AnimationUtils.animateView
import java.io.File import org.schabi.newpipe.util.FilePickerActivityHelper
import java.text.SimpleDateFormat import org.schabi.newpipe.util.NavigationHelper
import java.util.* import org.schabi.newpipe.util.OnClickGesture
import kotlin.math.floor import org.schabi.newpipe.util.ShareUtils
import kotlin.math.max import org.schabi.newpipe.util.ThemeHelper
class SubscriptionFragment : BaseStateFragment<SubscriptionState>() { class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
private lateinit var viewModel: SubscriptionViewModel private lateinit var viewModel: SubscriptionViewModel
@ -74,9 +97,9 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
setHasOptionsMenu(true) setHasOptionsMenu(true)
} }
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
// Fragment LifeCycle // Fragment LifeCycle
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -120,9 +143,9 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
disposables.dispose() disposables.dispose()
} }
////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////
// Menu // Menu
////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater) super.onCreateOptionsMenu(menu, inflater)
@ -150,7 +173,6 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
importExportItem.isExpanded = false importExportItem.isExpanded = false
importExportItem.notifyChanged(FeedImportExportItem.REFRESH_EXPANDED_STATUS) importExportItem.notifyChanged(FeedImportExportItem.REFRESH_EXPANDED_STATUS)
} }
} }
} }
@ -198,9 +220,9 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
} }
} }
////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////
// Fragment Views // Fragment Views
////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////
private fun setupInitialLayout() { private fun setupInitialLayout() {
Section().apply { Section().apply {
@ -243,7 +265,6 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
{ onExportSelected() }, { onExportSelected() },
importExportItemExpandedState ?: false) importExportItemExpandedState ?: false)
groupAdapter.add(Section(importExportItem, listOf(subscriptionsSection))) groupAdapter.add(Section(importExportItem, listOf(subscriptionsSection)))
} }
override fun initViews(rootView: View, savedInstanceState: Bundle?) { override fun initViews(rootView: View, savedInstanceState: Bundle?) {
@ -366,9 +387,9 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
items_list.post { feedGroupsSortMenuItem.notifyChanged(PAYLOAD_UPDATE_VISIBILITY_MENU_ITEM) } items_list.post { feedGroupsSortMenuItem.notifyChanged(PAYLOAD_UPDATE_VISIBILITY_MENU_ITEM) }
} }
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
// Contract // Contract
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
override fun showLoading() { override fun showLoading() {
super.showLoading() super.showLoading()
@ -380,9 +401,9 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
animateView(items_list, true, 200) animateView(items_list, true, 200)
} }
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
// Fragment Error Handling // Fragment Error Handling
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
override fun onError(exception: Throwable): Boolean { override fun onError(exception: Throwable): Boolean {
if (super.onError(exception)) return true if (super.onError(exception)) return true
@ -391,9 +412,9 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
return true return true
} }
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
// Grid Mode // Grid Mode
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
// TODO: Move these out of this class, as it can be reused // TODO: Move these out of this class, as it can be reused
@ -405,8 +426,8 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
getString(R.string.list_view_mode_auto_key) -> { getString(R.string.list_view_mode_auto_key) -> {
val configuration = resources.configuration val configuration = resources.configuration
(configuration.orientation == Configuration.ORIENTATION_LANDSCAPE (configuration.orientation == Configuration.ORIENTATION_LANDSCAPE &&
&& configuration.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE)) configuration.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE))
} }
getString(R.string.list_view_mode_grid_key) -> true getString(R.string.list_view_mode_grid_key) -> true
else -> false else -> false

View file

@ -6,11 +6,11 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.xwray.groupie.Group import com.xwray.groupie.Group
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import java.util.concurrent.TimeUnit
import org.schabi.newpipe.local.feed.FeedDatabaseManager import org.schabi.newpipe.local.feed.FeedDatabaseManager
import org.schabi.newpipe.local.subscription.item.ChannelItem import org.schabi.newpipe.local.subscription.item.ChannelItem
import org.schabi.newpipe.local.subscription.item.FeedGroupCardItem import org.schabi.newpipe.local.subscription.item.FeedGroupCardItem
import org.schabi.newpipe.util.DEFAULT_THROTTLE_TIMEOUT import org.schabi.newpipe.util.DEFAULT_THROTTLE_TIMEOUT
import java.util.concurrent.TimeUnit
class SubscriptionViewModel(application: Application) : AndroidViewModel(application) { class SubscriptionViewModel(application: Application) : AndroidViewModel(application) {
private var feedDatabaseManager: FeedDatabaseManager = FeedDatabaseManager(application) private var feedDatabaseManager: FeedDatabaseManager = FeedDatabaseManager(application)

View file

@ -32,4 +32,4 @@ class FeedGroupCarouselDecoration(context: Context) : RecyclerView.ItemDecoratio
outRect.right = marginStartEnd outRect.right = marginStartEnd
} }
} }
} }

View file

@ -22,19 +22,36 @@ import com.xwray.groupie.Section
import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder
import icepick.Icepick import icepick.Icepick
import icepick.State import icepick.State
import kotlinx.android.synthetic.main.dialog_feed_group_create.* import java.io.Serializable
import kotlinx.android.synthetic.main.dialog_feed_group_create.cancel_button
import kotlinx.android.synthetic.main.dialog_feed_group_create.confirm_button
import kotlinx.android.synthetic.main.dialog_feed_group_create.delete_button
import kotlinx.android.synthetic.main.dialog_feed_group_create.delete_screen_message
import kotlinx.android.synthetic.main.dialog_feed_group_create.group_name_input
import kotlinx.android.synthetic.main.dialog_feed_group_create.group_name_input_container
import kotlinx.android.synthetic.main.dialog_feed_group_create.icon_preview
import kotlinx.android.synthetic.main.dialog_feed_group_create.icon_selector
import kotlinx.android.synthetic.main.dialog_feed_group_create.options_root
import kotlinx.android.synthetic.main.dialog_feed_group_create.select_channel_button
import kotlinx.android.synthetic.main.dialog_feed_group_create.selected_subscription_count_view
import kotlinx.android.synthetic.main.dialog_feed_group_create.separator
import kotlinx.android.synthetic.main.dialog_feed_group_create.subscriptions_selector
import kotlinx.android.synthetic.main.dialog_feed_group_create.subscriptions_selector_header_info
import kotlinx.android.synthetic.main.dialog_feed_group_create.subscriptions_selector_list
import org.schabi.newpipe.R import org.schabi.newpipe.R
import org.schabi.newpipe.database.feed.model.FeedGroupEntity import org.schabi.newpipe.database.feed.model.FeedGroupEntity
import org.schabi.newpipe.database.subscription.SubscriptionEntity import org.schabi.newpipe.database.subscription.SubscriptionEntity
import org.schabi.newpipe.local.subscription.FeedGroupIcon import org.schabi.newpipe.local.subscription.FeedGroupIcon
import org.schabi.newpipe.local.subscription.dialog.FeedGroupDialog.ScreenState.* import org.schabi.newpipe.local.subscription.dialog.FeedGroupDialog.ScreenState.DeleteScreen
import org.schabi.newpipe.local.subscription.dialog.FeedGroupDialog.ScreenState.IconPickerScreen
import org.schabi.newpipe.local.subscription.dialog.FeedGroupDialog.ScreenState.InitialScreen
import org.schabi.newpipe.local.subscription.dialog.FeedGroupDialog.ScreenState.SubscriptionsPickerScreen
import org.schabi.newpipe.local.subscription.dialog.FeedGroupDialogViewModel.DialogEvent.ProcessingEvent import org.schabi.newpipe.local.subscription.dialog.FeedGroupDialogViewModel.DialogEvent.ProcessingEvent
import org.schabi.newpipe.local.subscription.dialog.FeedGroupDialogViewModel.DialogEvent.SuccessEvent import org.schabi.newpipe.local.subscription.dialog.FeedGroupDialogViewModel.DialogEvent.SuccessEvent
import org.schabi.newpipe.local.subscription.item.EmptyPlaceholderItem import org.schabi.newpipe.local.subscription.item.EmptyPlaceholderItem
import org.schabi.newpipe.local.subscription.item.PickerIconItem import org.schabi.newpipe.local.subscription.item.PickerIconItem
import org.schabi.newpipe.local.subscription.item.PickerSubscriptionItem import org.schabi.newpipe.local.subscription.item.PickerSubscriptionItem
import org.schabi.newpipe.util.ThemeHelper import org.schabi.newpipe.util.ThemeHelper
import java.io.Serializable
class FeedGroupDialog : DialogFragment() { class FeedGroupDialog : DialogFragment() {
private lateinit var viewModel: FeedGroupDialogViewModel private lateinit var viewModel: FeedGroupDialogViewModel
@ -120,9 +137,9 @@ class FeedGroupDialog : DialogFragment() {
showScreen(currentScreen) showScreen(currentScreen)
} }
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
// Setup // Setup
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
private fun setupListeners() { private fun setupListeners() {
delete_button.setOnClickListener { showScreen(DeleteScreen) } delete_button.setOnClickListener { showScreen(DeleteScreen) }
@ -294,9 +311,9 @@ class FeedGroupDialog : DialogFragment() {
} }
} }
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
// Screen Selector // Screen Selector
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
private fun showScreen(screen: ScreenState) { private fun showScreen(screen: ScreenState) {
currentScreen = screen currentScreen = screen
@ -330,9 +347,9 @@ class FeedGroupDialog : DialogFragment() {
} }
} }
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
// Utils // Utils
/////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////
private fun hideKeyboard() { private fun hideKeyboard() {
val inputMethodManager = requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager val inputMethodManager = requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
@ -363,4 +380,4 @@ class FeedGroupDialog : DialogFragment() {
return dialog return dialog
} }
} }
} }

View file

@ -16,7 +16,6 @@ import org.schabi.newpipe.local.feed.FeedDatabaseManager
import org.schabi.newpipe.local.subscription.FeedGroupIcon import org.schabi.newpipe.local.subscription.FeedGroupIcon
import org.schabi.newpipe.local.subscription.SubscriptionManager import org.schabi.newpipe.local.subscription.SubscriptionManager
class FeedGroupDialogViewModel(applicationContext: Context, val groupId: Long = FeedGroupEntity.GROUP_ALL_ID) : ViewModel() { class FeedGroupDialogViewModel(applicationContext: Context, val groupId: Long = FeedGroupEntity.GROUP_ALL_ID) : ViewModel() {
class Factory(val context: Context, val groupId: Long = FeedGroupEntity.GROUP_ALL_ID) : ViewModelProvider.Factory { class Factory(val context: Context, val groupId: Long = FeedGroupEntity.GROUP_ALL_ID) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
@ -84,4 +83,4 @@ class FeedGroupDialogViewModel(applicationContext: Context, val groupId: Long =
object ProcessingEvent : DialogEvent() object ProcessingEvent : DialogEvent()
object SuccessEvent : DialogEvent() object SuccessEvent : DialogEvent()
} }
} }

View file

@ -16,15 +16,15 @@ import com.xwray.groupie.TouchCallback
import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder
import icepick.Icepick import icepick.Icepick
import icepick.State import icepick.State
import kotlinx.android.synthetic.main.dialog_feed_group_reorder.* import java.util.Collections
import kotlinx.android.synthetic.main.dialog_feed_group_reorder.confirm_button
import kotlinx.android.synthetic.main.dialog_feed_group_reorder.feed_groups_list
import org.schabi.newpipe.R import org.schabi.newpipe.R
import org.schabi.newpipe.database.feed.model.FeedGroupEntity import org.schabi.newpipe.database.feed.model.FeedGroupEntity
import org.schabi.newpipe.local.subscription.dialog.FeedGroupReorderDialogViewModel.DialogEvent.ProcessingEvent import org.schabi.newpipe.local.subscription.dialog.FeedGroupReorderDialogViewModel.DialogEvent.ProcessingEvent
import org.schabi.newpipe.local.subscription.dialog.FeedGroupReorderDialogViewModel.DialogEvent.SuccessEvent import org.schabi.newpipe.local.subscription.dialog.FeedGroupReorderDialogViewModel.DialogEvent.SuccessEvent
import org.schabi.newpipe.local.subscription.item.FeedGroupReorderItem import org.schabi.newpipe.local.subscription.item.FeedGroupReorderItem
import org.schabi.newpipe.util.ThemeHelper import org.schabi.newpipe.util.ThemeHelper
import java.util.*
import kotlin.collections.ArrayList
class FeedGroupReorderDialog : DialogFragment() { class FeedGroupReorderDialog : DialogFragment() {
private lateinit var viewModel: FeedGroupReorderDialogViewModel private lateinit var viewModel: FeedGroupReorderDialogViewModel
@ -93,8 +93,11 @@ class FeedGroupReorderDialog : DialogFragment() {
private fun getItemTouchCallback(): SimpleCallback { private fun getItemTouchCallback(): SimpleCallback {
return object : TouchCallback() { return object : TouchCallback() {
override fun onMove(recyclerView: RecyclerView, source: RecyclerView.ViewHolder, override fun onMove(
target: RecyclerView.ViewHolder): Boolean { recyclerView: RecyclerView,
source: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
val sourceIndex = source.adapterPosition val sourceIndex = source.adapterPosition
val targetIndex = target.adapterPosition val targetIndex = target.adapterPosition
@ -109,4 +112,4 @@ class FeedGroupReorderDialog : DialogFragment() {
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, swipeDir: Int) {} override fun onSwiped(viewHolder: RecyclerView.ViewHolder, swipeDir: Int) {}
} }
} }
} }

View file

@ -49,4 +49,4 @@ class FeedGroupReorderDialogViewModel(application: Application) : AndroidViewMod
object ProcessingEvent : DialogEvent() object ProcessingEvent : DialogEvent()
object SuccessEvent : DialogEvent() object SuccessEvent : DialogEvent()
} }
} }

View file

@ -4,19 +4,21 @@ import android.content.Context
import com.nostra13.universalimageloader.core.ImageLoader import com.nostra13.universalimageloader.core.ImageLoader
import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder
import com.xwray.groupie.kotlinandroidextensions.Item import com.xwray.groupie.kotlinandroidextensions.Item
import kotlinx.android.synthetic.main.list_channel_item.* import kotlinx.android.synthetic.main.list_channel_item.itemAdditionalDetails
import kotlinx.android.synthetic.main.list_channel_item.itemChannelDescriptionView
import kotlinx.android.synthetic.main.list_channel_item.itemThumbnailView
import kotlinx.android.synthetic.main.list_channel_item.itemTitleView
import org.schabi.newpipe.R import org.schabi.newpipe.R
import org.schabi.newpipe.extractor.channel.ChannelInfoItem import org.schabi.newpipe.extractor.channel.ChannelInfoItem
import org.schabi.newpipe.util.ImageDisplayConstants import org.schabi.newpipe.util.ImageDisplayConstants
import org.schabi.newpipe.util.Localization import org.schabi.newpipe.util.Localization
import org.schabi.newpipe.util.OnClickGesture import org.schabi.newpipe.util.OnClickGesture
class ChannelItem( class ChannelItem(
private val infoItem: ChannelInfoItem, private val infoItem: ChannelInfoItem,
private val subscriptionId: Long = -1L, private val subscriptionId: Long = -1L,
var itemVersion: ItemVersion = ItemVersion.NORMAL, var itemVersion: ItemVersion = ItemVersion.NORMAL,
var gesturesListener: OnClickGesture<ChannelInfoItem>? = null var gesturesListener: OnClickGesture<ChannelInfoItem>? = null
) : Item() { ) : Item() {
override fun getId(): Long = if (subscriptionId == -1L) super.getId() else subscriptionId override fun getId(): Long = if (subscriptionId == -1L) super.getId() else subscriptionId
@ -62,4 +64,4 @@ class ChannelItem(
override fun getSpanSize(spanCount: Int, position: Int): Int { override fun getSpanSize(spanCount: Int, position: Int): Int {
return if (itemVersion == ItemVersion.GRID) 1 else spanCount return if (itemVersion == ItemVersion.GRID) 1 else spanCount
} }
} }

View file

@ -7,4 +7,4 @@ import org.schabi.newpipe.R
class EmptyPlaceholderItem : Item() { class EmptyPlaceholderItem : Item() {
override fun getLayout(): Int = R.layout.list_empty_view override fun getLayout(): Int = R.layout.list_empty_view
override fun bind(viewHolder: GroupieViewHolder, position: Int) {} override fun bind(viewHolder: GroupieViewHolder, position: Int) {}
} }

View file

@ -7,4 +7,4 @@ import org.schabi.newpipe.R
class FeedGroupAddItem : Item() { class FeedGroupAddItem : Item() {
override fun getLayout(): Int = R.layout.feed_group_add_new_item override fun getLayout(): Int = R.layout.feed_group_add_new_item
override fun bind(viewHolder: GroupieViewHolder, position: Int) {} override fun bind(viewHolder: GroupieViewHolder, position: Int) {}
} }

View file

@ -2,15 +2,16 @@ package org.schabi.newpipe.local.subscription.item
import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder
import com.xwray.groupie.kotlinandroidextensions.Item import com.xwray.groupie.kotlinandroidextensions.Item
import kotlinx.android.synthetic.main.feed_group_card_item.* import kotlinx.android.synthetic.main.feed_group_card_item.icon
import kotlinx.android.synthetic.main.feed_group_card_item.title
import org.schabi.newpipe.R import org.schabi.newpipe.R
import org.schabi.newpipe.database.feed.model.FeedGroupEntity import org.schabi.newpipe.database.feed.model.FeedGroupEntity
import org.schabi.newpipe.local.subscription.FeedGroupIcon import org.schabi.newpipe.local.subscription.FeedGroupIcon
data class FeedGroupCardItem( data class FeedGroupCardItem(
val groupId: Long = FeedGroupEntity.GROUP_ALL_ID, val groupId: Long = FeedGroupEntity.GROUP_ALL_ID,
val name: String, val name: String,
val icon: FeedGroupIcon val icon: FeedGroupIcon
) : Item() { ) : Item() {
constructor (feedGroupEntity: FeedGroupEntity) : this(feedGroupEntity.uid, feedGroupEntity.name, feedGroupEntity.icon) constructor (feedGroupEntity: FeedGroupEntity) : this(feedGroupEntity.uid, feedGroupEntity.name, feedGroupEntity.icon)
@ -27,4 +28,4 @@ data class FeedGroupCardItem(
viewHolder.title.text = name viewHolder.title.text = name
viewHolder.icon.setImageResource(icon.getDrawableRes(viewHolder.containerView.context)) viewHolder.icon.setImageResource(icon.getDrawableRes(viewHolder.containerView.context))
} }
} }

View file

@ -8,7 +8,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.xwray.groupie.GroupAdapter import com.xwray.groupie.GroupAdapter
import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder
import com.xwray.groupie.kotlinandroidextensions.Item import com.xwray.groupie.kotlinandroidextensions.Item
import kotlinx.android.synthetic.main.feed_item_carousel.* import kotlinx.android.synthetic.main.feed_item_carousel.recycler_view
import org.schabi.newpipe.R import org.schabi.newpipe.R
import org.schabi.newpipe.local.subscription.decoration.FeedGroupCarouselDecoration import org.schabi.newpipe.local.subscription.decoration.FeedGroupCarouselDecoration
@ -54,4 +54,4 @@ class FeedGroupCarouselItem(context: Context, private val carouselAdapter: Group
listState = linearLayoutManager?.onSaveInstanceState() listState = linearLayoutManager?.onSaveInstanceState()
} }
} }

View file

@ -6,19 +6,21 @@ import androidx.recyclerview.widget.ItemTouchHelper.DOWN
import androidx.recyclerview.widget.ItemTouchHelper.UP import androidx.recyclerview.widget.ItemTouchHelper.UP
import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder
import com.xwray.groupie.kotlinandroidextensions.Item import com.xwray.groupie.kotlinandroidextensions.Item
import kotlinx.android.synthetic.main.feed_group_reorder_item.* import kotlinx.android.synthetic.main.feed_group_reorder_item.group_icon
import kotlinx.android.synthetic.main.feed_group_reorder_item.group_name
import kotlinx.android.synthetic.main.feed_group_reorder_item.handle
import org.schabi.newpipe.R import org.schabi.newpipe.R
import org.schabi.newpipe.database.feed.model.FeedGroupEntity import org.schabi.newpipe.database.feed.model.FeedGroupEntity
import org.schabi.newpipe.local.subscription.FeedGroupIcon import org.schabi.newpipe.local.subscription.FeedGroupIcon
data class FeedGroupReorderItem( data class FeedGroupReorderItem(
val groupId: Long = FeedGroupEntity.GROUP_ALL_ID, val groupId: Long = FeedGroupEntity.GROUP_ALL_ID,
val name: String, val name: String,
val icon: FeedGroupIcon, val icon: FeedGroupIcon,
val dragCallback: ItemTouchHelper val dragCallback: ItemTouchHelper
) : Item() { ) : Item() {
constructor (feedGroupEntity: FeedGroupEntity, dragCallback: ItemTouchHelper) constructor (feedGroupEntity: FeedGroupEntity, dragCallback: ItemTouchHelper) :
: this(feedGroupEntity.uid, feedGroupEntity.name, feedGroupEntity.icon, dragCallback) this(feedGroupEntity.uid, feedGroupEntity.name, feedGroupEntity.icon, dragCallback)
override fun getId(): Long { override fun getId(): Long {
return when (groupId) { return when (groupId) {
@ -45,4 +47,4 @@ data class FeedGroupReorderItem(
override fun getDragDirs(): Int { override fun getDragDirs(): Int {
return UP or DOWN return UP or DOWN
} }
} }

View file

@ -9,7 +9,11 @@ import android.widget.TextView
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder
import com.xwray.groupie.kotlinandroidextensions.Item import com.xwray.groupie.kotlinandroidextensions.Item
import kotlinx.android.synthetic.main.feed_import_export_group.* import kotlinx.android.synthetic.main.feed_import_export_group.export_to_options
import kotlinx.android.synthetic.main.feed_import_export_group.import_export
import kotlinx.android.synthetic.main.feed_import_export_group.import_export_expand_icon
import kotlinx.android.synthetic.main.feed_import_export_group.import_export_options
import kotlinx.android.synthetic.main.feed_import_export_group.import_from_options
import org.schabi.newpipe.R import org.schabi.newpipe.R
import org.schabi.newpipe.extractor.NewPipe import org.schabi.newpipe.extractor.NewPipe
import org.schabi.newpipe.extractor.exceptions.ExtractionException import org.schabi.newpipe.extractor.exceptions.ExtractionException
@ -19,10 +23,10 @@ import org.schabi.newpipe.util.ThemeHelper
import org.schabi.newpipe.views.CollapsibleView import org.schabi.newpipe.views.CollapsibleView
class FeedImportExportItem( class FeedImportExportItem(
val onImportPreviousSelected: () -> Unit, val onImportPreviousSelected: () -> Unit,
val onImportFromServiceSelected: (Int) -> Unit, val onImportFromServiceSelected: (Int) -> Unit,
val onExportSelected: () -> Unit, val onExportSelected: () -> Unit,
var isExpanded: Boolean = false var isExpanded: Boolean = false
) : Item() { ) : Item() {
companion object { companion object {
const val REFRESH_EXPANDED_STATUS = 123 const val REFRESH_EXPANDED_STATUS = 123
@ -104,7 +108,6 @@ class FeedImportExportItem(
} catch (e: ExtractionException) { } catch (e: ExtractionException) {
throw RuntimeException("Services array contains an entry that it's not a valid service name ($serviceName)", e) throw RuntimeException("Services array contains an entry that it's not a valid service name ($serviceName)", e)
} }
} }
} }
@ -113,4 +116,4 @@ class FeedImportExportItem(
ThemeHelper.resolveResourceIdFromAttr(listHolder.context, R.attr.ic_save), listHolder) ThemeHelper.resolveResourceIdFromAttr(listHolder.context, R.attr.ic_save), listHolder)
previousBackupItem.setOnClickListener { onExportSelected() } previousBackupItem.setOnClickListener { onExportSelected() }
} }
} }

View file

@ -3,7 +3,7 @@ package org.schabi.newpipe.local.subscription.item
import android.view.View.OnClickListener import android.view.View.OnClickListener
import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder
import com.xwray.groupie.kotlinandroidextensions.Item import com.xwray.groupie.kotlinandroidextensions.Item
import kotlinx.android.synthetic.main.header_item.* import kotlinx.android.synthetic.main.header_item.header_title
import org.schabi.newpipe.R import org.schabi.newpipe.R
class HeaderItem(val title: String, private val onClickListener: (() -> Unit)? = null) : Item() { class HeaderItem(val title: String, private val onClickListener: (() -> Unit)? = null) : Item() {
@ -16,4 +16,4 @@ class HeaderItem(val title: String, private val onClickListener: (() -> Unit)? =
val listener: OnClickListener? = if (onClickListener != null) OnClickListener { onClickListener.invoke() } else null val listener: OnClickListener? = if (onClickListener != null) OnClickListener { onClickListener.invoke() } else null
viewHolder.root.setOnClickListener(listener) viewHolder.root.setOnClickListener(listener)
} }
} }

View file

@ -1,18 +1,21 @@
package org.schabi.newpipe.local.subscription.item package org.schabi.newpipe.local.subscription.item
import android.view.View.* import android.view.View.GONE
import android.view.View.OnClickListener
import android.view.View.VISIBLE
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder
import com.xwray.groupie.kotlinandroidextensions.Item import com.xwray.groupie.kotlinandroidextensions.Item
import kotlinx.android.synthetic.main.header_with_menu_item.* import kotlinx.android.synthetic.main.header_with_menu_item.header_menu_item
import kotlinx.android.synthetic.main.header_with_menu_item.header_title
import org.schabi.newpipe.R import org.schabi.newpipe.R
class HeaderWithMenuItem( class HeaderWithMenuItem(
val title: String, val title: String,
@DrawableRes val itemIcon: Int = 0, @DrawableRes val itemIcon: Int = 0,
var showMenuItem: Boolean = true, var showMenuItem: Boolean = true,
private val onClickListener: (() -> Unit)? = null, private val onClickListener: (() -> Unit)? = null,
private val menuItemOnClickListener: (() -> Unit)? = null private val menuItemOnClickListener: (() -> Unit)? = null
) : Item() { ) : Item() {
companion object { companion object {
const val PAYLOAD_UPDATE_VISIBILITY_MENU_ITEM = 1 const val PAYLOAD_UPDATE_VISIBILITY_MENU_ITEM = 1
@ -46,4 +49,4 @@ class HeaderWithMenuItem(
private fun updateMenuItemVisibility(viewHolder: GroupieViewHolder) { private fun updateMenuItemVisibility(viewHolder: GroupieViewHolder) {
viewHolder.header_menu_item.visibility = if (showMenuItem) VISIBLE else GONE viewHolder.header_menu_item.visibility = if (showMenuItem) VISIBLE else GONE
} }
} }

View file

@ -4,7 +4,7 @@ import android.content.Context
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder
import com.xwray.groupie.kotlinandroidextensions.Item import com.xwray.groupie.kotlinandroidextensions.Item
import kotlinx.android.synthetic.main.picker_icon_item.* import kotlinx.android.synthetic.main.picker_icon_item.icon_view
import org.schabi.newpipe.R import org.schabi.newpipe.R
import org.schabi.newpipe.local.subscription.FeedGroupIcon import org.schabi.newpipe.local.subscription.FeedGroupIcon
@ -17,4 +17,4 @@ class PickerIconItem(context: Context, val icon: FeedGroupIcon) : Item() {
override fun bind(viewHolder: GroupieViewHolder, position: Int) { override fun bind(viewHolder: GroupieViewHolder, position: Int) {
viewHolder.icon_view.setImageResource(iconRes) viewHolder.icon_view.setImageResource(iconRes)
} }
} }

View file

@ -5,7 +5,9 @@ import com.nostra13.universalimageloader.core.DisplayImageOptions
import com.nostra13.universalimageloader.core.ImageLoader import com.nostra13.universalimageloader.core.ImageLoader
import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder
import com.xwray.groupie.kotlinandroidextensions.Item import com.xwray.groupie.kotlinandroidextensions.Item
import kotlinx.android.synthetic.main.picker_subscription_item.* import kotlinx.android.synthetic.main.picker_subscription_item.selected_highlight
import kotlinx.android.synthetic.main.picker_subscription_item.thumbnail_view
import kotlinx.android.synthetic.main.picker_subscription_item.title_view
import org.schabi.newpipe.R import org.schabi.newpipe.R
import org.schabi.newpipe.database.subscription.SubscriptionEntity import org.schabi.newpipe.database.subscription.SubscriptionEntity
import org.schabi.newpipe.util.AnimationUtils import org.schabi.newpipe.util.AnimationUtils
@ -48,4 +50,4 @@ data class PickerSubscriptionItem(val subscriptionEntity: SubscriptionEntity, va
override fun getId(): Long { override fun getId(): Long {
return subscriptionEntity.uid return subscriptionEntity.uid
} }
} }

View file

@ -80,8 +80,8 @@ import org.schabi.newpipe.player.playqueue.PlayQueueItemHolder;
import org.schabi.newpipe.player.playqueue.PlayQueueItemTouchCallback; import org.schabi.newpipe.player.playqueue.PlayQueueItemTouchCallback;
import org.schabi.newpipe.player.resolver.MediaSourceTag; import org.schabi.newpipe.player.resolver.MediaSourceTag;
import org.schabi.newpipe.player.resolver.VideoPlaybackResolver; import org.schabi.newpipe.player.resolver.VideoPlaybackResolver;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.AndroidTvUtils; import org.schabi.newpipe.util.AndroidTvUtils;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.KoreUtil; import org.schabi.newpipe.util.KoreUtil;
import org.schabi.newpipe.util.ListHelper; import org.schabi.newpipe.util.ListHelper;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;

View file

@ -43,4 +43,4 @@ class DurationListPreference : ListPreference {
entries = newEntryTitles entries = newEntryTitles
} }
} }

View file

@ -5,8 +5,8 @@ import org.schabi.newpipe.streams.Mp4DashReader.Mdia;
import org.schabi.newpipe.streams.Mp4DashReader.Mp4DashChunk; import org.schabi.newpipe.streams.Mp4DashReader.Mp4DashChunk;
import org.schabi.newpipe.streams.Mp4DashReader.Mp4DashSample; import org.schabi.newpipe.streams.Mp4DashReader.Mp4DashSample;
import org.schabi.newpipe.streams.Mp4DashReader.Mp4Track; import org.schabi.newpipe.streams.Mp4DashReader.Mp4Track;
import org.schabi.newpipe.streams.Mp4DashReader.TrunEntry;
import org.schabi.newpipe.streams.Mp4DashReader.TrackKind; import org.schabi.newpipe.streams.Mp4DashReader.TrackKind;
import org.schabi.newpipe.streams.Mp4DashReader.TrunEntry;
import org.schabi.newpipe.streams.io.SharpStream; import org.schabi.newpipe.streams.io.SharpStream;
import java.io.IOException; import java.io.IOException;

View file

@ -79,4 +79,4 @@ class ExceptionUtils {
return false return false
} }
} }
} }

View file

@ -24,4 +24,4 @@ class UrlFinder {
return null return null
} }
} }
} }

View file

@ -25,6 +25,7 @@ import android.view.ViewTreeObserver;
import android.widget.SeekBar; import android.widget.SeekBar;
import androidx.appcompat.widget.AppCompatSeekBar; import androidx.appcompat.widget.AppCompatSeekBar;
import org.schabi.newpipe.util.AndroidTvUtils; import org.schabi.newpipe.util.AndroidTvUtils;
/** /**

View file

@ -6,8 +6,8 @@ import android.system.ErrnoException;
import android.system.OsConstants; import android.system.OsConstants;
import android.util.Log; import android.util.Log;
import androidx.annotation.Nullable;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.schabi.newpipe.DownloaderImpl; import org.schabi.newpipe.DownloaderImpl;

View file

@ -6,9 +6,10 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.NonNull;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;

View file

@ -3,9 +3,10 @@ package us.shandian.giga.io;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.net.Uri; import android.net.Uri;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import androidx.annotation.NonNull;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull;
import org.schabi.newpipe.streams.io.SharpStream; import org.schabi.newpipe.streams.io.SharpStream;
import java.io.FileInputStream; import java.io.FileInputStream;

View file

@ -8,6 +8,7 @@ import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.provider.DocumentsContract; import android.provider.DocumentsContract;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.documentfile.provider.DocumentFile; import androidx.documentfile.provider.DocumentFile;

View file

@ -7,10 +7,11 @@ import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.provider.DocumentsContract; import android.provider.DocumentsContract;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.documentfile.provider.DocumentFile; import androidx.documentfile.provider.DocumentFile;
import androidx.fragment.app.Fragment;
import org.schabi.newpipe.streams.io.SharpStream; import org.schabi.newpipe.streams.io.SharpStream;

View file

@ -1,6 +1,7 @@
package us.shandian.giga.ui.common; package us.shandian.giga.ui.common;
import android.os.Bundle; import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;

View file

@ -17,7 +17,6 @@ import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;

View file

@ -1,10 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto">
xmlns:tools="http://schemas.android.com/tools">
<item <item
android:id="@+id/menu_item_remove_watched" android:id="@+id/menu_item_remove_watched"
android:title="@string/remove_watched" android:title="@string/remove_watched"
app:showAsAction="never"/> app:showAsAction="never"/>
</menu> </menu>

View file

@ -27,4 +27,4 @@ class FeedGroupIconTest {
assertTrue("Repeated icon (current item: ${groupIcon.name} - ${groupIcon.id})", added) assertTrue("Repeated icon (current item: ${groupIcon.name} - ${groupIcon.id})", added)
} }
} }
} }

View file

@ -1,14 +1,14 @@
package org.schabi.newpipe.util package org.schabi.newpipe.util
import java.io.IOException
import java.io.InterruptedIOException
import java.net.SocketException
import javax.net.ssl.SSLException
import org.junit.Assert.assertFalse import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue import org.junit.Assert.assertTrue
import org.junit.Test import org.junit.Test
import org.schabi.newpipe.util.ExceptionUtils.Companion.hasAssignableCause import org.schabi.newpipe.util.ExceptionUtils.Companion.hasAssignableCause
import org.schabi.newpipe.util.ExceptionUtils.Companion.hasExactCause import org.schabi.newpipe.util.ExceptionUtils.Companion.hasExactCause
import java.io.IOException
import java.io.InterruptedIOException
import java.net.SocketException
import javax.net.ssl.SSLException
class ExceptionUtilsTest { class ExceptionUtilsTest {
@Test fun `assignable causes`() { @Test fun `assignable causes`() {
@ -66,4 +66,4 @@ class ExceptionUtilsTest {
assertFalse(hasExactCause(Exception(IllegalStateException(Exception(SocketException()))), IOException::class.java)) assertFalse(hasExactCause(Exception(IllegalStateException(Exception(SocketException()))), IOException::class.java))
assertFalse(hasExactCause(Exception(IllegalStateException(Exception(InterruptedIOException()))), IOException::class.java)) assertFalse(hasExactCause(Exception(IllegalStateException(Exception(InterruptedIOException()))), IOException::class.java))
} }
} }

View file

@ -96,4 +96,4 @@ class UrlFinderTest {
assertEquals("https://www.youtube.com/watch?v=dQw4w9WgXcQ", assertEquals("https://www.youtube.com/watch?v=dQw4w9WgXcQ",
UrlFinder.firstUrlFromInput("https://www.youtube.com/watch?v=dQw4w9WgXcQ\"Not PartOfTheUrl")) UrlFinder.firstUrlFromInput("https://www.youtube.com/watch?v=dQw4w9WgXcQ\"Not PartOfTheUrl"))
} }
} }