diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 34541df..c29aa7f 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -7,7 +7,7 @@
-
+
+
+
+
diff --git a/app/build.gradle b/app/build.gradle
index e433447..0eb0963 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -3,11 +3,13 @@ plugins {
id 'com.google.gms.google-services'
id 'com.google.firebase.crashlytics'
id 'kotlin-android'
-
+ id 'kotlinx-serialization'
+ id 'org.jetbrains.kotlin.android'
+ id 'kotlin-kapt'
}
android {
- compileSdkVersion 33
+ compileSdkVersion 34
buildToolsVersion "30.0.3"
lintOptions {
@@ -24,8 +26,8 @@ android {
applicationId "com.mugames.vidsnap"
minSdkVersion 21
targetSdkVersion 33
- versionCode 13
- versionName "6.1.0"
+ versionCode 14
+ versionName "6.1.1"
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -76,21 +78,24 @@ dependencies {
implementation 'com.google.firebase:firebase-analytics'
implementation 'androidx.appcompat:appcompat:1.6.1'
- implementation "androidx.activity:activity-ktx:1.6.1"
- implementation "androidx.fragment:fragment-ktx:1.5.5"
- implementation 'com.google.android.material:material:1.8.0'
+ implementation "androidx.activity:activity-ktx:1.7.2"
+ implementation "androidx.fragment:fragment-ktx:1.6.0"
+ implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
- implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.0'
- implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.0'
+ implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.1'
+ implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.3.0'
- implementation 'androidx.core:core-ktx:1.9.0'
+ implementation 'androidx.core:core-ktx:1.10.1'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.preference:preference-ktx:1.2.0'
implementation 'com.google.firebase:firebase-config:'
- implementation 'com.google.firebase:firebase-database:20.1.0'
+ implementation 'com.google.firebase:firebase-database:20.2.2'
+
+ // Ktor
+ implementation 'io.ktor:ktor-client-android:2.3.1'
//Fetch
implementation "androidx.tonyodev.fetch2okhttp:xfetch2okhttp:3.1.6"
@@ -106,7 +111,8 @@ dependencies {
implementation 'androidx.browser:browser:1.5.0'
//FCM
- implementation 'com.google.firebase:firebase-messaging-ktx:23.1.2'
+ implementation 'com.google.firebase:firebase-messaging-ktx:23.2.0'
+ implementation 'androidx.core:core-ktx:+'
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.1'
@@ -118,18 +124,13 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
+ implementation 'androidx.paging:paging-runtime-ktx:3.1.1'
//Room
- def room_version = "2.5.0"
+ def room_version = "2.6.0-alpha02"
implementation "androidx.room:room-runtime:$room_version"
- annotationProcessor "androidx.room:room-compiler:$room_version"
- // optional - RxJava2 support for Room
- implementation "androidx.room:room-rxjava2:$room_version"
- // optional - RxJava3 support for Room
- implementation "androidx.room:room-rxjava3:$room_version"
- // optional - Guava support for Room, including Optional and ListenableFuture
- implementation "androidx.room:room-guava:$room_version"
- // optional - Test helpers
- testImplementation "androidx.room:room-testing:$room_version"
+ implementation "androidx.room:room-ktx:$room_version"
+ kapt "androidx.room:room-compiler:$room_version"
+
//LeakCanary
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1'
@@ -143,7 +144,7 @@ dependencies {
implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.2'
//VidSnapKit
- implementation 'io.github.udhayarajan:VidSnapKit:4.0.3'
+ implementation 'io.github.udhayarajan:VidSnapKit:5.6.13'
}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index 3a28fb0..cbc04ca 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -41,3 +41,4 @@
-dontwarn org.osgi.framework.BundleContext
-dontwarn org.osgi.framework.FrameworkUtil
-dontwarn org.osgi.framework.ServiceReference
+-dontwarn org.slf4j.impl.StaticLoggerBinder
\ No newline at end of file
diff --git a/app/src/main/java/com/mugames/vidsnap/database/History.java b/app/src/main/java/com/mugames/vidsnap/database/History.java
deleted file mode 100644
index 9f95c3c..0000000
--- a/app/src/main/java/com/mugames/vidsnap/database/History.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * This file is part of VidSnap.
- *
- * VidSnap is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * any later version.
- *
- * VidSnap is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with VidSnap. If not, see .
- */
-
-package com.mugames.vidsnap.database;
-
-import android.net.Uri;
-import android.text.format.DateFormat;
-
-import androidx.room.ColumnInfo;
-import androidx.room.Entity;
-import androidx.room.PrimaryKey;
-import androidx.room.TypeConverters;
-
-import com.mugames.vidsnap.utility.bundles.DownloadDetails;
-import com.mugames.vidsnap.utility.UtilityClass;
-
-import java.util.Date;
-import java.util.Objects;
-
-@Entity(tableName = "HISTORY")
-@TypeConverters(DateConverter.class)
-public class History {
-
- @PrimaryKey(autoGenerate = true)
- public int id;
- public String fileName;
- public String fileType;
- public String source;
- public Date date;
- public String size;
- public String uriString;
- public String image;
- @ColumnInfo(name = "source_url")
- public String sourceUrl;
-
- public History() {
- }
-
-
- public History(DownloadDetails details, Uri uri) {
- this.fileName = details.fileName;
- this.fileType = details.fileType;
- this.source = details.src;
- this.date = DateConverter.toDate(new Date().getTime());
- this.size = String.valueOf(details.videoSize);
- this.uriString = uri.toString();
- sourceUrl = details.srcUrl;
- image = UtilityClass.bitmapToString(details.getThumbNail());
- }
-
- public Uri getUri() {
- return Uri.parse(uriString);
- }
-
- public String getDate() {
- return (String) DateFormat.format("dd-MM-yyyy", date);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- History history = (History) o;
- return Objects.equals(fileName, history.fileName) &&
- Objects.equals(fileType, history.fileType) &&
- Objects.equals(source, history.source) &&
- Objects.equals(date, history.date) &&
- Objects.equals(size, history.size) &&
- Objects.equals(uriString, history.uriString) &&
- Objects.equals(image, history.image) &&
- Objects.equals(sourceUrl, history.sourceUrl);
- }
-}
diff --git a/app/src/main/java/com/mugames/vidsnap/database/History.kt b/app/src/main/java/com/mugames/vidsnap/database/History.kt
new file mode 100644
index 0000000..cbe0258
--- /dev/null
+++ b/app/src/main/java/com/mugames/vidsnap/database/History.kt
@@ -0,0 +1,92 @@
+/*
+ * This file is part of VidSnap.
+ *
+ * VidSnap is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * VidSnap is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with VidSnap. If not, see .
+ */
+package com.mugames.vidsnap.database
+
+import android.net.Uri
+import android.text.format.DateFormat
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import androidx.room.TypeConverters
+import com.mugames.vidsnap.utility.UtilityClass
+import com.mugames.vidsnap.utility.bundles.DownloadDetails
+import java.util.Date
+
+@Entity(tableName = "HISTORY")
+@TypeConverters(DateConverter::class)
+class History {
+ @JvmField
+ @PrimaryKey(autoGenerate = true)
+ var id = 0
+ @JvmField
+ var fileName: String? = null
+ @JvmField
+ var fileType: String? = null
+ @JvmField
+ var source: String? = null
+ @JvmField
+ var date: Date? = null
+ @JvmField
+ var size: String? = null
+ @JvmField
+ var uriString: String? = null
+ @JvmField
+ var image: String? = null
+
+ @JvmField
+ @ColumnInfo(name = "source_url")
+ var sourceUrl: String? = null
+
+ constructor() {}
+ constructor(details: DownloadDetails, uri: Uri) {
+ fileName = details.fileName
+ fileType = details.fileType
+ source = details.src
+ date = DateConverter.toDate(Date().time)
+ size = details.videoSize.toString()
+ uriString = uri.toString()
+ sourceUrl = details.srcUrl
+ image = UtilityClass.bitmapToString(details.thumbNail)
+ }
+
+ val uri: Uri
+ get() = Uri.parse(uriString)
+
+ fun getDate(): String {
+ return DateFormat.format("dd-MM-yyyy", date) as String
+ }
+
+ override fun equals(o: Any?): Boolean {
+ if (this === o) return true
+ if (o == null || javaClass != o.javaClass) return false
+ val history = o as History
+ return fileName == history.fileName && fileType == history.fileType && source == history.source && date == history.date && size == history.size && uriString == history.uriString && image == history.image && sourceUrl == history.sourceUrl
+ }
+
+ override fun hashCode(): Int {
+ var result = id
+ result = 31 * result + (fileName?.hashCode() ?: 0)
+ result = 31 * result + (fileType?.hashCode() ?: 0)
+ result = 31 * result + (source?.hashCode() ?: 0)
+ result = 31 * result + (date?.hashCode() ?: 0)
+ result = 31 * result + (size?.hashCode() ?: 0)
+ result = 31 * result + (uriString?.hashCode() ?: 0)
+ result = 31 * result + (image?.hashCode() ?: 0)
+ result = 31 * result + (sourceUrl?.hashCode() ?: 0)
+ return result
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mugames/vidsnap/database/HistoryDao.java b/app/src/main/java/com/mugames/vidsnap/database/HistoryDao.kt
similarity index 60%
rename from app/src/main/java/com/mugames/vidsnap/database/HistoryDao.java
rename to app/src/main/java/com/mugames/vidsnap/database/HistoryDao.kt
index 47a7d4a..a012730 100644
--- a/app/src/main/java/com/mugames/vidsnap/database/HistoryDao.java
+++ b/app/src/main/java/com/mugames/vidsnap/database/HistoryDao.kt
@@ -14,32 +14,28 @@
* You should have received a copy of the GNU General Public License
* along with VidSnap. If not, see .
*/
+package com.mugames.vidsnap.database
-package com.mugames.vidsnap.database;
-
-import androidx.lifecycle.LiveData;
-import androidx.room.Dao;
-import androidx.room.Delete;
-import androidx.room.Insert;
-import androidx.room.Query;
-
-import java.util.List;
+import androidx.lifecycle.LiveData
+import androidx.room.Dao
+import androidx.room.Delete
+import androidx.room.Insert
+import androidx.room.Query
@Dao
-public interface HistoryDao {
-
+interface HistoryDao {
@Insert
- void insertItem(History history);
+ fun insertItem(history: History)
@Query("DELETE FROM HISTORY")
- void deleteTable();
-
- @Query("SELECT * from HISTORY ORDER BY date DESC")
- LiveData> getAllValues();
+ fun deleteTable()
@Query("SELECT COUNT(1) FROM HISTORY")
- LiveData isEntryAvailable();
+ fun isEntryAvailable(): LiveData?
+
+ @Query("SELECT * from HISTORY ORDER BY date DESC LIMIT :limit OFFSET :offset")
+ suspend fun paginatedHistory(limit: Int, offset: Int): List?
@Delete
- void removeItem(History history);
-}
+ fun removeItem(history: History)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mugames/vidsnap/database/HistoryDatabase.java b/app/src/main/java/com/mugames/vidsnap/database/HistoryDatabase.java
deleted file mode 100644
index 4af614a..0000000
--- a/app/src/main/java/com/mugames/vidsnap/database/HistoryDatabase.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * This file is part of VidSnap.
- *
- * VidSnap is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * any later version.
- *
- * VidSnap is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with VidSnap. If not, see .
- */
-
-package com.mugames.vidsnap.database;
-
-import static com.mugames.vidsnap.storage.AppPref.STATIC_CACHE;
-import static com.mugames.vidsnap.storage.AppPref.db_name;
-
-import android.content.Context;
-import android.database.Cursor;
-
-import androidx.annotation.NonNull;
-import androidx.room.Database;
-import androidx.room.Room;
-import androidx.room.RoomDatabase;
-import androidx.room.migration.Migration;
-import androidx.sqlite.db.SupportSQLiteDatabase;
-
-import com.mugames.vidsnap.storage.AppPref;
-import com.mugames.vidsnap.utility.UtilityClass;
-
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-
-@Database(entities = {History.class}, version = 4)
-public abstract class HistoryDatabase extends RoomDatabase {
-
-
- private static volatile HistoryDatabase instance;
-
- static Migration migration1_2 = new Migration(1, 2) {
- @Override
- public void migrate(@NonNull SupportSQLiteDatabase database) {
- database.execSQL("CREATE TABLE HISTORY_NEW (id INTEGER NOT NULL , fileName TEXT, fileType TEXT, source TEXT, date TEXT, size TEXT, uriString TEXT, image TEXT, PRIMARY KEY(id))");
- Cursor cursor = database.query("SELECT * FROM HISTORY");
- while (cursor.moveToNext()) {
- String value = migrateLogic1_3(cursor, 1, 2, 0);
- database.execSQL("INSERT INTO HISTORY_NEW (id,fileName,fileType,source,date,size,uriString,image) VALUES(" + value + ")");
- }
- database.execSQL("DROP TABLE HISTORY");
- database.execSQL("ALTER TABLE HISTORY_NEW RENAME TO HISTORY");
- }
- };
-
-
- static Migration migration2_3 = new Migration(2, 3) {
- @Override
- public void migrate(@NonNull SupportSQLiteDatabase database) {
- database.execSQL("CREATE TABLE HISTORY_NEW (id INTEGER NOT NULL , fileName TEXT, fileType TEXT, source TEXT, date INTRGER, size TEXT, uriString TEXT, image TEXT, PRIMARY KEY(id))");
- Cursor cursor = database.query("SELECT * FROM HISTORY");
- int i = 0;
- while (cursor.moveToNext()) {
- String value = migrateLogic1_3(cursor, 2, 3, i++);
- database.execSQL("INSERT INTO HISTORY_NEW (id,fileName,fileType,source,date,size,uriString,image) VALUES(" + value + ")");
- }
- database.execSQL("DROP TABLE HISTORY");
- database.execSQL("ALTER TABLE HISTORY_NEW RENAME TO HISTORY");
- }
- };
-
- static Migration migration3_4 = new Migration(3, 4) {
- @Override
- public void migrate(@NonNull SupportSQLiteDatabase database) {
- database.execSQL("Alter table history add column source_url TEXT");
- }
- };
-
- static String migrateLogic1_3(Cursor cursor, int from, int to, int i) {
- int id = cursor.getInt(0);
- String fileName = cursor.getString(1);
- String fileType = cursor.getString(2);
- String src = cursor.getString(3);
- String date = cursor.getString(4);
- String size = cursor.getString(5);
- String uriString = cursor.getString(6);
- if (from == 1 && to == 2) {
- byte[] thumbNail = cursor.getBlob(7);
- int width = cursor.getInt(8);
- int height = cursor.getInt(9);
-
- fileType = fileType.replaceAll("\\.", "");
- String thumbnailString = UtilityClass.bitmapToString(UtilityClass.bytesToBitmap(thumbNail, width, height));
- return id + ",\"" + fileName + "\",\"" + fileType + "\",\"" + src + "\",\"" + date + "\",\"" + size + "\",\"" + uriString + "\",\"" + thumbnailString + "\"";
- } else if (from == 2 && to == 3) {
- Long lDate = parseForDate(date, i);
- String thumbnailString = cursor.getString(7);
-
- return id + ",\"" + fileName + "\",\"" + fileType + "\",\"" + src + "\"," + lDate + ",\"" + size + "\",\"" + uriString + "\",\"" + thumbnailString + "\"";
- }
- return null;
- }
-
- private static Long parseForDate(String date, int index) {
- SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
- try {
- Date date1 = simpleDateFormat.parse(date);
- return date1.getTime() + index;
- } catch (ParseException e) {
- e.printStackTrace();
- }
- return null;
- }
-
- public abstract HistoryDao historyDao();
-
- public static HistoryDatabase getInstance(Context context) {
- if (instance == null) {
- synchronized (HistoryDatabase.class) {
- if (instance == null) {
- instance = Room.databaseBuilder(context.getApplicationContext(), HistoryDatabase.class, AppPref.getInstance(context).getCachePath(STATIC_CACHE) + db_name)
- .addMigrations(migration1_2, migration2_3, migration3_4)
- .build();
- }
- }
- }
- return instance;
- }
-}
diff --git a/app/src/main/java/com/mugames/vidsnap/database/HistoryDatabase.kt b/app/src/main/java/com/mugames/vidsnap/database/HistoryDatabase.kt
new file mode 100644
index 0000000..a2bdb0f
--- /dev/null
+++ b/app/src/main/java/com/mugames/vidsnap/database/HistoryDatabase.kt
@@ -0,0 +1,129 @@
+/*
+ * This file is part of VidSnap.
+ *
+ * VidSnap is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * VidSnap is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with VidSnap. If not, see .
+ */
+package com.mugames.vidsnap.database
+
+import android.content.Context
+import android.database.Cursor
+import androidx.room.Database
+import androidx.room.Room.databaseBuilder
+import androidx.room.RoomDatabase
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+import com.mugames.vidsnap.storage.AppPref
+import com.mugames.vidsnap.utility.UtilityClass
+import java.text.ParseException
+import java.text.SimpleDateFormat
+import java.util.Locale
+
+@Database(entities = [History::class], version = 4)
+abstract class HistoryDatabase : RoomDatabase() {
+ abstract fun historyDao(): HistoryDao
+
+ companion object {
+ @Volatile
+ private var instance: HistoryDatabase? = null
+ var migration1_2: Migration = object : Migration(1, 2) {
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL("CREATE TABLE HISTORY_NEW (id INTEGER NOT NULL , fileName TEXT, fileType TEXT, source TEXT, date TEXT, size TEXT, uriString TEXT, image TEXT, PRIMARY KEY(id))")
+ val cursor = database.query("SELECT * FROM HISTORY")
+ while (cursor.moveToNext()) {
+ val value = migrateLogic1_3(cursor, 1, 2, 0)
+ database.execSQL("INSERT INTO HISTORY_NEW (id,fileName,fileType,source,date,size,uriString,image) VALUES($value)")
+ }
+ database.execSQL("DROP TABLE HISTORY")
+ database.execSQL("ALTER TABLE HISTORY_NEW RENAME TO HISTORY")
+ }
+ }
+ var migration2_3: Migration = object : Migration(2, 3) {
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL("CREATE TABLE HISTORY_NEW (id INTEGER NOT NULL , fileName TEXT, fileType TEXT, source TEXT, date INTRGER, size TEXT, uriString TEXT, image TEXT, PRIMARY KEY(id))")
+ val cursor = database.query("SELECT * FROM HISTORY")
+ var i = 0
+ while (cursor.moveToNext()) {
+ val value = migrateLogic1_3(cursor, 2, 3, i++)
+ database.execSQL("INSERT INTO HISTORY_NEW (id,fileName,fileType,source,date,size,uriString,image) VALUES($value)")
+ }
+ database.execSQL("DROP TABLE HISTORY")
+ database.execSQL("ALTER TABLE HISTORY_NEW RENAME TO HISTORY")
+ }
+ }
+ var migration3_4: Migration = object : Migration(3, 4) {
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL("Alter table history add column source_url TEXT")
+ }
+ }
+
+ fun migrateLogic1_3(cursor: Cursor, from: Int, to: Int, i: Int): String? {
+ val id = cursor.getInt(0)
+ val fileName = cursor.getString(1)
+ var fileType = cursor.getString(2)
+ val src = cursor.getString(3)
+ val date = cursor.getString(4)
+ val size = cursor.getString(5)
+ val uriString = cursor.getString(6)
+ if (from == 1 && to == 2) {
+ val thumbNail = cursor.getBlob(7)
+ val width = cursor.getInt(8)
+ val height = cursor.getInt(9)
+ fileType = fileType.replace("\\.".toRegex(), "")
+ val thumbnailString = UtilityClass.bitmapToString(
+ UtilityClass.bytesToBitmap(
+ thumbNail,
+ width,
+ height
+ )
+ )
+ return "$id,\"$fileName\",\"$fileType\",\"$src\",\"$date\",\"$size\",\"$uriString\",\"$thumbnailString\""
+ } else if (from == 2 && to == 3) {
+ val lDate = parseForDate(date, i)
+ val thumbnailString = cursor.getString(7)
+ return "$id,\"$fileName\",\"$fileType\",\"$src\",$lDate,\"$size\",\"$uriString\",\"$thumbnailString\""
+ }
+ return null
+ }
+
+ private fun parseForDate(date: String, index: Int): Long? {
+ val simpleDateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
+ try {
+ val date1 = simpleDateFormat.parse(date)
+ if (date1 != null) {
+ return date1.time + index
+ }
+ } catch (e: ParseException) {
+ e.printStackTrace()
+ }
+ return null
+ }
+
+ @JvmStatic
+ fun getInstance(context: Context): HistoryDatabase {
+ return instance ?: synchronized(this) {
+ val instance = databaseBuilder(
+ context.applicationContext,
+ HistoryDatabase::class.java,
+ AppPref.getInstance(context)
+ .getCachePath(AppPref.STATIC_CACHE) + AppPref.db_name
+ )
+ .addMigrations(migration1_2, migration2_3, migration3_4)
+ .build()
+
+ this.instance = instance
+ instance
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mugames/vidsnap/database/HistoryPagingSource.kt b/app/src/main/java/com/mugames/vidsnap/database/HistoryPagingSource.kt
new file mode 100644
index 0000000..e667abb
--- /dev/null
+++ b/app/src/main/java/com/mugames/vidsnap/database/HistoryPagingSource.kt
@@ -0,0 +1,61 @@
+/*
+ * This file is part of VidSnap.
+ *
+ * VidSnap is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ * VidSnap is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with VidSnap. If not, see .
+ *
+ */
+
+package com.mugames.vidsnap.database
+
+import androidx.paging.PagingSource
+import androidx.paging.PagingState
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.collectLatest
+import kotlin.math.max
+
+
+/**
+ * @author Udhaya
+ * Created on 25-07-2023
+ */
+
+private const val STARTING_KEY = 0
+
+class HistoryPagingSource(private val historyDao: HistoryDao) : PagingSource() {
+ // The refresh key is used for the initial load of the next PagingSource, after invalidation
+ override fun getRefreshKey(state: PagingState): Int? {
+ val anchorPosition = state.anchorPosition ?: return null
+ val history = state.closestItemToPosition(anchorPosition) ?: return null
+ return ensureValidKey(key = history.id - (state.config.pageSize / 2))
+ }
+
+ private fun ensureValidKey(key: Int) = max(STARTING_KEY, key)
+
+ override suspend fun load(params: LoadParams): LoadResult {
+ // If params.key is null, it is the first load, so we start loading with STARTING_KEY
+ val startKey = params.key ?: STARTING_KEY
+ val data = historyDao.paginatedHistory(params.loadSize, startKey) ?: emptyList()
+
+ return LoadResult.Page(
+ data = data,
+ prevKey = when (startKey) {
+ STARTING_KEY -> null
+ else -> when (val prevKey = ensureValidKey(key = startKey - params.loadSize)) {
+ // We're at the start, there's nothing more to load
+ STARTING_KEY -> null
+ else -> prevKey
+ }
+ },
+ nextKey = if (data.isEmpty()) null else startKey + params.loadSize
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mugames/vidsnap/database/HistoryRepository.java b/app/src/main/java/com/mugames/vidsnap/database/HistoryRepository.java
index 52787b1..985b38d 100644
--- a/app/src/main/java/com/mugames/vidsnap/database/HistoryRepository.java
+++ b/app/src/main/java/com/mugames/vidsnap/database/HistoryRepository.java
@@ -17,9 +17,10 @@
package com.mugames.vidsnap.database;
-import android.app.Application;
+import android.content.Context;
import androidx.lifecycle.LiveData;
+import androidx.paging.PagingSource;
import java.util.List;
@@ -28,10 +29,10 @@ public class HistoryRepository {
LiveData> allValues;
LiveData dataAvailable;
- public HistoryRepository(Application application) {
- HistoryDatabase historyDatabase = HistoryDatabase.getInstance(application);
+ public HistoryRepository(Context context) {
+ HistoryDatabase historyDatabase = HistoryDatabase.getInstance(context);
historyDao = historyDatabase.historyDao();
- allValues = historyDao.getAllValues();
+// allValues = historyDao.getAllValues();
dataAvailable = historyDao.isEntryAvailable();
}
@@ -40,7 +41,11 @@ public void insertItem(History history) {
}
public void clear() {
- new DeleteAllHistoryAsync(historyDao).backgroundTask();
+ new DeleteAllHistoryAsync(historyDao, null).backgroundTask();
+ }
+
+ public void delete(History history) {
+ new DeleteAllHistoryAsync(historyDao, history).backgroundTask();
}
public LiveData> getAllValues() {
@@ -68,17 +73,25 @@ public void backgroundTask(History history) {
private static class DeleteAllHistoryAsync {
HistoryDao historyDao;
+ History history;
- public DeleteAllHistoryAsync(HistoryDao historyDao) {
+ public DeleteAllHistoryAsync(HistoryDao historyDao, History history) {
this.historyDao = historyDao;
+ this.history = history;
}
public void backgroundTask() {
Thread thread = new Thread(() -> {
- historyDao.deleteTable();
+ if (history == null)
+ historyDao.deleteTable();
+ else
+ historyDao.removeItem(history);
});
thread.start();
}
}
+ public PagingSource getPaginationSource() {
+ return new HistoryPagingSource(historyDao);
+ }
}
diff --git a/app/src/main/java/com/mugames/vidsnap/network/Downloader.java b/app/src/main/java/com/mugames/vidsnap/network/Downloader.java
index 0eb3e21..35d3638 100644
--- a/app/src/main/java/com/mugames/vidsnap/network/Downloader.java
+++ b/app/src/main/java/com/mugames/vidsnap/network/Downloader.java
@@ -80,6 +80,7 @@
import com.mugames.vidsnap.utility.Statics;
import com.mugames.vidsnap.ui.activities.MainActivity;
+import com.mugames.vidsnapkit.MimeType;
import com.tonyodev.fetch2.Download;
import com.tonyodev.fetch2.Fetch;
import com.tonyodev.fetch2.FetchConfiguration;
@@ -412,6 +413,9 @@ synchronized void onDoneDownload(String finalPath, String finalMime) {
return;
}
}
+ if (finalMime.equals("")){
+ finalMime = MimeType.Companion.fromCodecs(finalPath,"");
+ }
copyVideoToDestination(finalPath, finalMime);
removeDownloader();
}
diff --git a/app/src/main/java/com/mugames/vidsnap/ui/activities/MainActivity.java b/app/src/main/java/com/mugames/vidsnap/ui/activities/MainActivity.java
index 9969ba1..09682cb 100644
--- a/app/src/main/java/com/mugames/vidsnap/ui/activities/MainActivity.java
+++ b/app/src/main/java/com/mugames/vidsnap/ui/activities/MainActivity.java
@@ -662,12 +662,9 @@ public void saveVideos() {
e.printStackTrace();
}
for (DownloadDetails details : activityViewModel.tempDetails) {
- FileUtil.scanMedia(this, details.pathUri.toString(), new MediaScannerConnection.OnScanCompletedListener() {
- @Override
- public void onScanCompleted(String s, Uri uri) {
- History history = new History(details, uri);
- new Thread(() -> HistoryDatabase.getInstance(getApplicationContext()).historyDao().insertItem(history)).start();
- }
+ FileUtil.scanMedia(this, details.pathUri.toString(), (s, uri) -> {
+ History history = new History(details, uri);
+ new Thread(() -> HistoryDatabase.getInstance(getApplicationContext()).historyDao().insertItem(history)).start();
});
}
diff --git a/app/src/main/java/com/mugames/vidsnap/ui/adapters/HistoryRecyclerViewAdapter.java b/app/src/main/java/com/mugames/vidsnap/ui/adapters/HistoryRecyclerViewAdapter.java
index fa11735..7e9bd03 100644
--- a/app/src/main/java/com/mugames/vidsnap/ui/adapters/HistoryRecyclerViewAdapter.java
+++ b/app/src/main/java/com/mugames/vidsnap/ui/adapters/HistoryRecyclerViewAdapter.java
@@ -37,6 +37,7 @@
import androidx.annotation.NonNull;
import androidx.lifecycle.LifecycleOwner;
+import androidx.paging.PagingDataAdapter;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListAdapter;
import androidx.recyclerview.widget.RecyclerView;
@@ -57,7 +58,7 @@
import java.util.concurrent.TimeUnit;
-public class HistoryRecyclerViewAdapter extends ListAdapter {
+public class HistoryRecyclerViewAdapter extends PagingDataAdapter {
String TAG = Statics.TAG + ":HistoryRecyclerViewAdapter";
@@ -107,7 +108,7 @@ public void onBindViewHolder(@NotNull final ViewHolder holder, int position) {
holder.name.setText(currentHistory.fileName + currentHistory.fileType);
else
holder.name.setText(currentHistory.fileName + "." + currentHistory.fileType);
- holder.src.setText(currentHistory.source);
+ holder.src.setText(currentHistory.source.substring(0, Math.min(currentHistory.source.length(), 20)));
holder.date.setText(currentHistory.getDate());
holder.size.setText(formatFileSize(Long.parseLong(currentHistory.size), false));
holder.cardView.setVisibility(View.GONE);
@@ -198,6 +199,7 @@ private void deleteThis(History currentHistory) {
new Thread(() -> HistoryDatabase.getInstance(activity).historyDao().removeItem(currentHistory)).start();
return;
}
+ activity.getContentResolver().delete(currentHistory.getUri(), null, null);
historyViewModel.deleteThisItem(currentHistory);
}
diff --git a/app/src/main/java/com/mugames/vidsnap/ui/fragments/HistoryFragment.java b/app/src/main/java/com/mugames/vidsnap/ui/fragments/HistoryFragment.java
deleted file mode 100644
index d709e4c..0000000
--- a/app/src/main/java/com/mugames/vidsnap/ui/fragments/HistoryFragment.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * This file is part of VidSnap.
- *
- * VidSnap is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * any later version.
- *
- * VidSnap is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with VidSnap. If not, see .
- */
-
-package com.mugames.vidsnap.ui.fragments;
-
-import android.Manifest;
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentSender;
-import android.content.pm.PackageManager;
-import android.os.Build;
-import android.os.Bundle;
-
-import androidx.activity.result.ActivityResult;
-import androidx.activity.result.ActivityResultCallback;
-import androidx.activity.result.ActivityResultLauncher;
-import androidx.activity.result.ActivityResultRegistry;
-import androidx.activity.result.IntentSenderRequest;
-import androidx.activity.result.contract.ActivityResultContract;
-import androidx.activity.result.contract.ActivityResultContracts;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.core.app.ActivityCompat;
-import androidx.core.app.ActivityOptionsCompat;
-import androidx.core.content.ContextCompat;
-import androidx.fragment.app.Fragment;
-import androidx.lifecycle.Observer;
-import androidx.lifecycle.ViewModelProvider;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Toast;
-
-import com.mugames.vidsnap.database.History;
-import com.mugames.vidsnap.databinding.FragmentHistoryBinding;
-import com.mugames.vidsnap.ui.activities.MainActivity;
-import com.mugames.vidsnap.ui.viewmodels.HistoryViewModel;
-import com.mugames.vidsnap.R;
-import com.mugames.vidsnap.utility.Statics;
-import com.mugames.vidsnap.ui.adapters.HistoryRecyclerViewAdapter;
-
-import java.util.List;
-
-/**
- * This fragment keeps track of Download history data
- * Usually get displayed when Menu->Downloads is clicked
- */
-public class HistoryFragment extends Fragment {
-
- String TAG = Statics.TAG + ":HistoryFragment";
-
- HistoryViewModel historyViewModel;
- ActivityResultLauncher deleteLauncher;
- FragmentHistoryBinding binding;
-
- HistoryRecyclerViewAdapter adapter;
-
- private ActivityResultLauncher readPermissionResultLauncher;
-
- public HistoryFragment() {
- }
-
- public static HistoryFragment newInstance() {
- return new HistoryFragment();
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- historyViewModel = new ViewModelProvider(this,
- (ViewModelProvider.Factory) ViewModelProvider
- .AndroidViewModelFactory
- .getInstance(requireActivity().getApplication())
- ).get(HistoryViewModel.class);
-
- deleteLauncher = registerForActivityResult(new ActivityResultContracts.StartIntentSenderForResult(), (ActivityResultCallback) result -> {
- if (result.getResultCode() == Activity.RESULT_OK) {
- historyViewModel.deletePendingUri();
- } else Toast.makeText(requireContext(), "Unable to delete", Toast.LENGTH_SHORT).show();
- });
-
- readPermissionResultLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(), result -> {
- if (result) {
- loadData();
- } else {
- Toast.makeText(requireContext(), "Permission Denied", Toast.LENGTH_SHORT).show();
- requireActivity().onBackPressed();
- }
- });
- }
-
- @Override
- public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- binding = FragmentHistoryBinding.inflate(inflater, container, false);
- View view = binding.getRoot();
- adapter = new HistoryRecyclerViewAdapter(getViewLifecycleOwner(), historyViewModel);
-
- Context context = view.getContext();
- RecyclerView recyclerView = binding.recyclerView;
- recyclerView.setLayoutManager(new LinearLayoutManager(context));
- recyclerView.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.list_background));
- recyclerView.setAdapter(adapter);
- binding.loadingIndicator.show();
- if (ActivityCompat.checkSelfPermission(requireActivity(), Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
- readPermissionResultLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE);
- } else {
- loadData();
- }
-
- historyViewModel.getIntentSender().observe(getViewLifecycleOwner(), intentSender -> {
- if (intentSender != null) {
- deleteLauncher.launch(new IntentSenderRequest.Builder(intentSender).build());
- }
- });
- swapViewVisibility(false);
- binding.noRecordContainer.errorReason.setText("No old downloads found");
- return view;
- }
-
- private void swapViewVisibility(boolean hasElement) {
- if (hasElement) {
- binding.recyclerView.setVisibility(View.VISIBLE);
- binding.recyclerView.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.list_background));
- binding.noRecordContainer.noRecordFragmentParent.setVisibility(View.GONE);
- } else {
- binding.recyclerView.setVisibility(View.GONE);
- binding.noRecordContainer.noRecordFragmentParent.setVisibility(View.VISIBLE);
- binding.getRoot().setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.notification_color));
- }
- }
-
- private void loadData() {
- historyViewModel.getAllValues().observe(getViewLifecycleOwner(), new Observer>() {
- @Override
- public void onChanged(List histories) {
- binding.loadingIndicator.hide();
- swapViewVisibility(!histories.isEmpty());
- adapter.submitList(histories);
- }
- });
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/mugames/vidsnap/ui/fragments/HistoryFragment.kt b/app/src/main/java/com/mugames/vidsnap/ui/fragments/HistoryFragment.kt
new file mode 100644
index 0000000..35e0079
--- /dev/null
+++ b/app/src/main/java/com/mugames/vidsnap/ui/fragments/HistoryFragment.kt
@@ -0,0 +1,184 @@
+/*
+ * This file is part of VidSnap.
+ *
+ * VidSnap is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * VidSnap is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with VidSnap. If not, see .
+ */
+package com.mugames.vidsnap.ui.fragments
+
+import android.Manifest
+import android.app.Activity
+import android.content.pm.PackageManager
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Toast
+import androidx.activity.result.ActivityResult
+import androidx.activity.result.ActivityResultLauncher
+import androidx.activity.result.IntentSenderRequest
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
+import androidx.core.view.isVisible
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.viewModels
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import androidx.paging.LoadState
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.mugames.vidsnap.R
+import com.mugames.vidsnap.database.HistoryRepository
+import com.mugames.vidsnap.databinding.FragmentHistoryBinding
+import com.mugames.vidsnap.ui.adapters.HistoryRecyclerViewAdapter
+import com.mugames.vidsnap.ui.viewmodels.HistoryViewModel
+import com.mugames.vidsnap.ui.viewmodels.factory.HistoryViewModelFactory
+import com.mugames.vidsnap.utility.Statics
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.launch
+
+/**
+ * This fragment keeps track of Download history data
+ * Usually get displayed when Menu->Downloads is clicked
+ */
+class HistoryFragment : Fragment() {
+ private var TAG = Statics.TAG + ":HistoryFragment"
+ private val historyViewModel by viewModels(
+ factoryProducer = { HistoryViewModelFactory(this, HistoryRepository(context)) }
+ )
+ private lateinit var deleteLauncher: ActivityResultLauncher
+
+ private lateinit var binding: FragmentHistoryBinding
+
+ private lateinit var adapter: HistoryRecyclerViewAdapter
+
+ private lateinit var readPermissionResultLauncher: ActivityResultLauncher
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ deleteLauncher = registerForActivityResult(
+ ActivityResultContracts.StartIntentSenderForResult()
+ ) { result: ActivityResult ->
+ if (result.resultCode == Activity.RESULT_OK) {
+ historyViewModel.deletePendingUri(requireContext().contentResolver)
+ } else Toast.makeText(requireContext(), "Unable to delete", Toast.LENGTH_SHORT)
+ .show()
+ }
+
+ readPermissionResultLauncher =
+ registerForActivityResult(ActivityResultContracts.RequestPermission()) { result: Boolean ->
+ if (result) {
+ loadData()
+ } else {
+ Toast.makeText(requireContext(), "Permission Denied", Toast.LENGTH_SHORT).show()
+ requireActivity().onBackPressed()
+ }
+ }
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ binding = FragmentHistoryBinding.inflate(inflater, container, false)
+ adapter = HistoryRecyclerViewAdapter(viewLifecycleOwner, historyViewModel)
+
+ val recyclerView = binding.recyclerView
+ recyclerView.layoutManager = LinearLayoutManager(context)
+ recyclerView.setBackgroundColor(
+ ContextCompat.getColor(
+ requireContext(),
+ R.color.list_background
+ )
+ )
+
+ binding.loadingIndicator.show()
+ recyclerView.adapter = adapter
+ adapter.addLoadStateListener {
+ if (it.source.refresh is LoadState.Loading || it.source.prepend is LoadState.Loading || it.source.append is LoadState.Loading) {
+ binding.loadingIndicator.show()
+ } else
+ binding.loadingIndicator.hide()
+ swapViewVisibility(adapter.itemCount != 0)
+ }
+
+ if (ActivityCompat.checkSelfPermission(
+ requireActivity(),
+ Manifest.permission.READ_EXTERNAL_STORAGE
+ ) == PackageManager.PERMISSION_DENIED
+ ) {
+ readPermissionResultLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
+ } else {
+ loadData()
+ }
+ historyViewModel.intentSender.observe(viewLifecycleOwner) { intentSender ->
+ if (intentSender != null) {
+ deleteLauncher.launch(IntentSenderRequest.Builder(intentSender).build())
+ }
+ }
+ swapViewVisibility(false)
+ binding.noRecordContainer.errorReason.text = "No old downloads found"
+ return binding.root
+ }
+
+ private fun swapViewVisibility(hasElement: Boolean) {
+ if (hasElement) {
+ binding.recyclerView.visibility = View.VISIBLE
+ binding.recyclerView.setBackgroundColor(
+ ContextCompat.getColor(
+ requireContext(),
+ R.color.list_background
+ )
+ )
+ binding.noRecordContainer.noRecordFragmentParent.visibility = View.GONE
+ } else {
+ binding.recyclerView.visibility = View.GONE
+ binding.noRecordContainer.noRecordFragmentParent.visibility = View.VISIBLE
+ binding.root.setBackgroundColor(
+ ContextCompat.getColor(
+ requireContext(),
+ R.color.notification_color
+ )
+ )
+ }
+ }
+
+ private fun loadData() {
+ val values = historyViewModel.pagedValue
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ values.collectLatest {
+ adapter.submitData(it)
+ }
+ }
+ }
+
+// lifecycleScope.launch {
+// repeatOnLifecycle(Lifecycle.State.STARTED) {
+// adapter.loadStateFlow.collect {
+////
+// }
+// }
+// }
+ }
+
+ companion object {
+ @JvmStatic
+ fun newInstance(): HistoryFragment {
+ return HistoryFragment()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mugames/vidsnap/ui/fragments/VideoFragment.java b/app/src/main/java/com/mugames/vidsnap/ui/fragments/VideoFragment.java
index 002fa18..6c79a6b 100644
--- a/app/src/main/java/com/mugames/vidsnap/ui/fragments/VideoFragment.java
+++ b/app/src/main/java/com/mugames/vidsnap/ui/fragments/VideoFragment.java
@@ -49,10 +49,10 @@
import com.bumptech.glide.request.FutureTarget;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.firebase.crashlytics.FirebaseCrashlytics;
import com.mugames.vidsnap.R;
import com.mugames.vidsnap.storage.AppPref;
-import com.mugames.vidsnap.storage.FileUtil;
import com.mugames.vidsnap.ui.activities.MainActivity;
import com.mugames.vidsnap.ui.adapters.DownloadableAdapter;
import com.mugames.vidsnap.ui.viewmodels.VideoFragmentViewModelKt;
@@ -218,7 +218,7 @@ public void startProcess(String link) {
((UtilityInterface.DialogueInterface) activity).show("Analysing");
if (viewModel != null) {
if (viewModel.onClickAnalysis(link, (MainActivity) requireActivity(), true) == null)
- unLockAnalysis();
+ askForDirectDownload();
else {
viewModel.clearDetails();
viewModel.getDownloadDetails().srcUrl = link;
@@ -241,6 +241,23 @@ public void onChanged(UtilityClass.LoginDetailsProvider loginDetailsProvider) {
}
}
+ private void askForDirectDownload() {
+ unLockAnalysis();
+ ((UtilityInterface.DialogueInterface) activity).dismiss();
+ var dialog = new MaterialAlertDialogBuilder(requireContext())
+ .setTitle("Direct Download?")
+ .setMessage("We can't identify what kind of url you have given. Would to like to just download the content in the URL?")
+ .setPositiveButton("Yes", (dialog1, which) -> directDownload())
+ .setNegativeButton("No", (dialog1, which) -> dialog1.dismiss());
+ dialog.create().show();
+ }
+
+ private void directDownload() {
+ viewModel.getDownloadDetails().srcUrl = link;
+ viewModel.directDownloadFrom(link);
+ }
+
+
private void hideKeyboard(View v) {
if (v == null)
v = activity.getCurrentFocus();
@@ -328,6 +345,21 @@ void actionForSOLOFile(Formats formats) {
QualityFragment dialogFragment = new QualityFragment();
dialogFragment.setOnDownloadButtonClicked(this::safeDismissBottomSheet);
+ if (formats.fileMime.get(0).equals("")) {
+ var downloadDetails = new ArrayList();
+ var downloadDetail = new DownloadDetails();
+ downloadDetail.src = viewModel.getFormats().src;
+ downloadDetail.srcUrl = link;
+ downloadDetail.fileMime = "";
+ downloadDetail.videoURL = link;
+ downloadDetail.videoSize = viewModel.getFormats().videoSizes.get(0);
+ downloadDetail.pathUri = AppPref.getInstance(requireContext()).getSavePath();
+ downloadDetails.add(downloadDetail);
+ activity.download(downloadDetails);
+ viewModel.clearDetails();
+ return;
+ }
+
Glide.with(requireContext())
.asBitmap()
.load(Uri.parse(formats.thumbNailsURL.get(0)))
diff --git a/app/src/main/java/com/mugames/vidsnap/ui/viewmodels/HistoryViewModel.java b/app/src/main/java/com/mugames/vidsnap/ui/viewmodels/HistoryViewModel.java
deleted file mode 100644
index c56d334..0000000
--- a/app/src/main/java/com/mugames/vidsnap/ui/viewmodels/HistoryViewModel.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * This file is part of VidSnap.
- *
- * VidSnap is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * any later version.
- *
- * VidSnap is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with VidSnap. If not, see .
- */
-
-package com.mugames.vidsnap.ui.viewmodels;
-
-import android.app.Application;
-import android.app.RecoverableSecurityException;
-import android.content.IntentSender;
-import android.os.Build;
-
-import androidx.annotation.NonNull;
-import androidx.lifecycle.AndroidViewModel;
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.MutableLiveData;
-
-import com.mugames.vidsnap.database.History;
-import com.mugames.vidsnap.database.HistoryDatabase;
-import com.mugames.vidsnap.database.HistoryRepository;
-
-import org.jetbrains.annotations.NotNull;
-
-import java.util.List;
-
-public class HistoryViewModel extends AndroidViewModel {
- HistoryRepository repository;
- LiveData> allValues;
- History pendingHistory;
-
- MutableLiveData intentSenderLiveData = new MutableLiveData<>();
-
- public HistoryViewModel(@NonNull @NotNull Application application) {
- super(application);
- repository = new HistoryRepository(application);
- allValues = repository.getAllValues();
- }
-
- public void insert(History history) {
- repository.insertItem(history);
- }
-
- public void clearRepository() {
- repository.clear();
- }
-
-
- public LiveData> getAllValues() {
- return allValues;
- }
-
- public void deleteThisItem(History currentHistory) {
- try {
- getApplication().getContentResolver().delete(
- currentHistory.getUri(),
- null,
- null
- );
- new Thread(()-> HistoryDatabase.getInstance(getApplication().getApplicationContext()).historyDao().removeItem(currentHistory)).start();
- } catch (Exception e) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- if (e instanceof RecoverableSecurityException) {
- pendingHistory = currentHistory;
- intentSenderLiveData.postValue(((RecoverableSecurityException) e).getUserAction().getActionIntent().getIntentSender());
- return;
- }
- }
- throw e;
- }
- }
-
-
- public LiveData getIntentSender(){
- return intentSenderLiveData;
- }
-
- public void deletePendingUri() {
- if (pendingHistory != null){
- deleteThisItem(pendingHistory);
- pendingHistory = null;
- }
- }
-}
diff --git a/app/src/main/java/com/mugames/vidsnap/ui/viewmodels/HistoryViewModel.kt b/app/src/main/java/com/mugames/vidsnap/ui/viewmodels/HistoryViewModel.kt
new file mode 100644
index 0000000..727c87c
--- /dev/null
+++ b/app/src/main/java/com/mugames/vidsnap/ui/viewmodels/HistoryViewModel.kt
@@ -0,0 +1,84 @@
+/*
+ * This file is part of VidSnap.
+ *
+ * VidSnap is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * VidSnap is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with VidSnap. If not, see .
+ */
+package com.mugames.vidsnap.ui.viewmodels
+
+import android.app.RecoverableSecurityException
+import android.content.ContentResolver
+import android.content.Context
+import android.content.IntentSender
+import android.os.Build
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import androidx.paging.Pager
+import androidx.paging.PagingConfig
+import androidx.paging.PagingData
+import androidx.paging.cachedIn
+import com.mugames.vidsnap.database.History
+import com.mugames.vidsnap.database.HistoryRepository
+import kotlinx.coroutines.flow.Flow
+
+class HistoryViewModel(private val repository: HistoryRepository) : ViewModel() {
+
+ var pagedValue: Flow> = Pager(
+ config = PagingConfig(ITEMS_PER_PAGE, enablePlaceholders = false, initialLoadSize = ITEMS_PER_PAGE),
+ pagingSourceFactory = { repository.paginationSource }
+ ).flow.cachedIn(viewModelScope)
+
+ private var pendingHistory: History? = null
+ private var intentSenderLiveData = MutableLiveData()
+
+
+ fun insert(history: History?) {
+ repository.insertItem(history)
+ }
+
+ fun clearRepository() {
+ repository.clear()
+ }
+
+ fun deleteThisItem(currentHistory: History) {
+ try {
+ repository.delete(currentHistory)
+ } catch (e: Exception) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ if (e is RecoverableSecurityException) {
+ pendingHistory = currentHistory
+ intentSenderLiveData.postValue(e.userAction.actionIntent.intentSender)
+ return
+ }
+ }
+ throw e
+ }
+ }
+
+ val intentSender: LiveData
+ get() = intentSenderLiveData
+
+ fun deletePendingUri(resolver: ContentResolver) {
+ if (pendingHistory != null) {
+ resolver.delete(pendingHistory!!.uri, null, null)
+ deleteThisItem(pendingHistory!!)
+ pendingHistory = null
+ }
+ }
+
+ companion object {
+ private const val ITEMS_PER_PAGE = 10
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mugames/vidsnap/ui/viewmodels/VideoFragmentViewModel.java b/app/src/main/java/com/mugames/vidsnap/ui/viewmodels/VideoFragmentViewModel.java
index 0f2b6ea..1911cd8 100644
--- a/app/src/main/java/com/mugames/vidsnap/ui/viewmodels/VideoFragmentViewModel.java
+++ b/app/src/main/java/com/mugames/vidsnap/ui/viewmodels/VideoFragmentViewModel.java
@@ -56,9 +56,6 @@ public Extractor onClickAnalysis(String url, MainActivity activity, boolean isUs
extractor = new Twitter();
} else if (url.contains("fb") || url.contains("facebook")) {
extractor = new Facebook();
- } else {
- extractor = null;
- activity.error("URL Seems to be wrong", null);
}
if (extractor != null) {
extractor.setContext(getApplication());
@@ -74,7 +71,7 @@ public Extractor onClickAnalysis(String url, MainActivity activity, boolean isUs
}
- public String getUrlLink(){
+ public String getUrlLink() {
return urlLink;
}
@@ -145,5 +142,7 @@ public void clearLoginAlert() {
}
//To prevent same instance of `details` it must be `null`ed before extraction
- public void clearDetails(){details = null;}
+ public void clearDetails() {
+ details = null;
+ }
}
diff --git a/app/src/main/java/com/mugames/vidsnap/ui/viewmodels/VideoFragmentViewModelKt.kt b/app/src/main/java/com/mugames/vidsnap/ui/viewmodels/VideoFragmentViewModelKt.kt
index 3c390c2..88f9e8d 100644
--- a/app/src/main/java/com/mugames/vidsnap/ui/viewmodels/VideoFragmentViewModelKt.kt
+++ b/app/src/main/java/com/mugames/vidsnap/ui/viewmodels/VideoFragmentViewModelKt.kt
@@ -25,10 +25,14 @@ import com.mugames.vidsnap.utility.SingleEventLiveData
import com.mugames.vidsnap.utility.UtilityClass
import com.mugames.vidsnapkit.dataholders.Formats
import com.mugames.vidsnapkit.dataholders.Result
+import com.mugames.vidsnapkit.dataholders.VideoResource
import com.mugames.vidsnapkit.extractor.Extractor
import com.mugames.vidsnapkit.extractor.Facebook
import com.mugames.vidsnapkit.extractor.Instagram
+import com.mugames.vidsnapkit.network.HttpRequestService
import kotlinx.coroutines.launch
+import java.net.URL
+
/**
* @author Udhaya
@@ -54,6 +58,8 @@ class VideoFragmentViewModelKt(application: Application) : VideoFragmentViewMode
isUserClickCall: Boolean
): com.mugames.vidsnap.extractor.Extractor? {
urlLink = url
+ if (url.contains("cdninstagram"))
+ return null
isCookieUsed = !isUserClickCall
extractorKt = Extractor.findExtractor(url)
extractorKt?.let {
@@ -154,6 +160,32 @@ class VideoFragmentViewModelKt(application: Application) : VideoFragmentViewMode
isShareOnly = false
formats = com.mugames.vidsnap.utility.bundles.Formats()
}
+
+ fun directDownloadFrom(url: String) {
+ viewModelScope.launch {
+ val path = URL(url).path
+ val parts = path.split("/".toRegex()).dropLastWhile { it.isEmpty() }
+ .toTypedArray()
+ val formats = Formats(
+ title = "Unrecognized direct download",
+ src = if (parts.isNotEmpty()) parts[parts.size - 1] else "Direct download",
+ url = url,
+ videoData = mutableListOf(
+ VideoResource(
+ url = url,
+ mimeType = "",
+ quality = "",
+ size = HttpRequestService.create().getSize(url)
+ )
+ )
+ )
+ resultLiveData.postValue(
+ Result.Success(
+ formats = listOf(formats)
+ )
+ )
+ }
+ }
}
class EmptyExtractor : com.mugames.vidsnap.extractor.Extractor("Nothing") {
diff --git a/app/src/main/java/com/mugames/vidsnap/ui/viewmodels/factory/HistoryViewModelFactory.kt b/app/src/main/java/com/mugames/vidsnap/ui/viewmodels/factory/HistoryViewModelFactory.kt
new file mode 100644
index 0000000..9cd3a80
--- /dev/null
+++ b/app/src/main/java/com/mugames/vidsnap/ui/viewmodels/factory/HistoryViewModelFactory.kt
@@ -0,0 +1,48 @@
+/*
+ * This file is part of VidSnap.
+ *
+ * VidSnap is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ * VidSnap is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with VidSnap. If not, see .
+ *
+ */
+
+package com.mugames.vidsnap.ui.viewmodels.factory
+
+import androidx.lifecycle.AbstractSavedStateViewModelFactory
+import androidx.lifecycle.SavedStateHandle
+import androidx.lifecycle.ViewModel
+import androidx.savedstate.SavedStateRegistryOwner
+import com.mugames.vidsnap.database.History
+import com.mugames.vidsnap.database.HistoryRepository
+import com.mugames.vidsnap.ui.viewmodels.HistoryViewModel
+
+/**
+ * @author Udhaya
+ * Created on 25-07-2023
+ */
+
+class HistoryViewModelFactory(
+ owner: SavedStateRegistryOwner,
+ private val repository: HistoryRepository
+) : AbstractSavedStateViewModelFactory(owner, null) {
+
+ override fun create(
+ key: String,
+ modelClass: Class,
+ handle: SavedStateHandle
+ ): T {
+ if (modelClass.isAssignableFrom(HistoryViewModel::class.java)) {
+ @Suppress("UNCHECKED_CAST")
+ return HistoryViewModel(repository) as T
+ }
+ throw IllegalArgumentException("Unknown ViewModel class")
+ }
+}
diff --git a/app/src/main/java/com/mugames/vidsnap/utility/DownloadReceiver.java b/app/src/main/java/com/mugames/vidsnap/utility/DownloadReceiver.java
index ffa4087..cdb94dc 100644
--- a/app/src/main/java/com/mugames/vidsnap/utility/DownloadReceiver.java
+++ b/app/src/main/java/com/mugames/vidsnap/utility/DownloadReceiver.java
@@ -111,7 +111,10 @@ protected void onReceiveResult(int resultCode, Bundle resultData) {
DownloadDetails details = DownloadDetails.findDetails(id);
File file = new File(FileUtil.getPathFromTreeUri(context, outputUri));
details.fileName = file.getName().split("\\.")[0];
- details.fileType = file.getName().split("\\.")[1];
+ var fileType = "";
+ if (file.getName().split("\\.").length > 1)
+ fileType = file.getName().split("\\.")[1];
+ details.fileType = fileType;
details.fileMime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(details.fileType);
downloadDetailsList.remove(DownloadDetails.findDetails(id));
scan(outputUri.toString(), downloadDetails);
@@ -194,7 +197,7 @@ void notificationFailed(Bundle resultData) {
PendingIntent pendingIntent = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
pendingIntent = PendingIntent.getActivity(context, 110, browserIntent, PendingIntent.FLAG_IMMUTABLE);
- }else {
+ } else {
pendingIntent = PendingIntent.getActivity(context, 110, browserIntent, 0);
}
builder.setPriority(NotificationCompat.PRIORITY_HIGH)
diff --git a/app/src/main/java/com/mugames/vidsnap/utility/bundles/DownloadDetails.java b/app/src/main/java/com/mugames/vidsnap/utility/bundles/DownloadDetails.java
index 6fbeb9f..870d035 100644
--- a/app/src/main/java/com/mugames/vidsnap/utility/bundles/DownloadDetails.java
+++ b/app/src/main/java/com/mugames/vidsnap/utility/bundles/DownloadDetails.java
@@ -67,7 +67,7 @@ public class DownloadDetails implements Parcelable {
public long videoSize;
public long audioSize;
- private Uri thumbNailPath;
+ private Uri thumbNailPath = Uri.parse("");
int thumbWidth;
int thumbHeight;
@@ -182,14 +182,14 @@ public static DownloadDetails findDetails(int id) {
downloadDetailsList) {
if (details.id == id) return details;
}
- throw new IllegalArgumentException("id: "+id+" has no details\nAvailable are"+downloadDetailsList);
+ throw new IllegalArgumentException("id: " + id + " has no details\nAvailable are" + downloadDetailsList);
}
@Nullable
- public static DownloadDetails findDetailsOrNull(int id){
- try{
+ public static DownloadDetails findDetailsOrNull(int id) {
+ try {
return findDetails(id);
- }catch (IllegalArgumentException e){
+ } catch (IllegalArgumentException e) {
e.printStackTrace();
return null;
}
diff --git a/app/src/main/res/layout/fragment_history.xml b/app/src/main/res/layout/fragment_history.xml
index 3d7ee37..5a05210 100644
--- a/app/src/main/res/layout/fragment_history.xml
+++ b/app/src/main/res/layout/fragment_history.xml
@@ -17,12 +17,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
-
-
+
+
diff --git a/build.gradle b/build.gradle
index b250bc2..ca2e932 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,6 +1,6 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = '1.8.0'
+ ext.kotlin_version = '1.8.21'
repositories {
google() // Google's Maven repository
@@ -8,10 +8,11 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:8.0.0'
+ classpath 'com.android.tools.build:gradle:8.0.2'
classpath 'com.google.gms:google-services:4.3.15'
- classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.4'
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.7'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0"
+ classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}