Convert RecentSearchDao, RecentSearchDataSource and RecentSearchRepository to kotlin
This commit is contained in:
parent
c49b44f212
commit
003beec5b6
@ -1,36 +1,28 @@
|
|||||||
package awais.instagrabber.db.dao;
|
package awais.instagrabber.db.dao
|
||||||
|
|
||||||
import androidx.room.Dao;
|
import androidx.room.*
|
||||||
import androidx.room.Delete;
|
import awais.instagrabber.db.entities.RecentSearch
|
||||||
import androidx.room.Insert;
|
import awais.instagrabber.models.enums.FavoriteType
|
||||||
import androidx.room.Query;
|
|
||||||
import androidx.room.Update;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import awais.instagrabber.db.entities.RecentSearch;
|
|
||||||
import awais.instagrabber.models.enums.FavoriteType;
|
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
public interface RecentSearchDao {
|
interface RecentSearchDao {
|
||||||
|
|
||||||
@Query("SELECT * FROM recent_searches ORDER BY last_searched_on DESC")
|
@Query("SELECT * FROM recent_searches ORDER BY last_searched_on DESC")
|
||||||
List<RecentSearch> getAllRecentSearches();
|
suspend fun getAllRecentSearches(): List<RecentSearch>
|
||||||
|
|
||||||
@Query("SELECT * FROM recent_searches WHERE `ig_id` = :igId AND `type` = :type")
|
@Query("SELECT * FROM recent_searches WHERE `ig_id` = :igId AND `type` = :type")
|
||||||
RecentSearch getRecentSearchByIgIdAndType(String igId, FavoriteType type);
|
suspend fun getRecentSearchByIgIdAndType(igId: String, type: FavoriteType): RecentSearch?
|
||||||
|
|
||||||
@Query("SELECT * FROM recent_searches WHERE instr(`name`, :query) > 0")
|
@Query("SELECT * FROM recent_searches WHERE instr(`name`, :query) > 0")
|
||||||
List<RecentSearch> findRecentSearchesWithNameContaining(String query);
|
suspend fun findRecentSearchesWithNameContaining(query: String): List<RecentSearch>
|
||||||
|
|
||||||
@Insert
|
@Insert
|
||||||
Long insertRecentSearch(RecentSearch recentSearch);
|
suspend fun insertRecentSearch(recentSearch: RecentSearch)
|
||||||
|
|
||||||
@Update
|
@Update
|
||||||
void updateRecentSearch(RecentSearch recentSearch);
|
suspend fun updateRecentSearch(recentSearch: RecentSearch)
|
||||||
|
|
||||||
@Delete
|
@Delete
|
||||||
void deleteRecentSearch(RecentSearch recentSearch);
|
suspend fun deleteRecentSearch(recentSearch: RecentSearch)
|
||||||
|
|
||||||
// @Query("DELETE from recent_searches")
|
// @Query("DELETE from recent_searches")
|
||||||
// void deleteAllRecentSearches();
|
// void deleteAllRecentSearches();
|
||||||
|
@ -1,57 +1,43 @@
|
|||||||
package awais.instagrabber.db.datasources;
|
package awais.instagrabber.db.datasources
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context
|
||||||
|
import awais.instagrabber.db.AppDatabase
|
||||||
|
import awais.instagrabber.db.dao.RecentSearchDao
|
||||||
|
import awais.instagrabber.db.entities.RecentSearch
|
||||||
|
import awais.instagrabber.models.enums.FavoriteType
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
class RecentSearchDataSource private constructor(private val recentSearchDao: RecentSearchDao) {
|
||||||
|
|
||||||
import java.util.List;
|
suspend fun getRecentSearchByIgIdAndType(igId: String, type: FavoriteType): RecentSearch? =
|
||||||
|
recentSearchDao.getRecentSearchByIgIdAndType(igId, type)
|
||||||
|
|
||||||
import awais.instagrabber.db.AppDatabase;
|
suspend fun getAllRecentSearches(): List<RecentSearch> = recentSearchDao.getAllRecentSearches()
|
||||||
import awais.instagrabber.db.dao.RecentSearchDao;
|
|
||||||
import awais.instagrabber.db.entities.RecentSearch;
|
|
||||||
import awais.instagrabber.models.enums.FavoriteType;
|
|
||||||
|
|
||||||
public class RecentSearchDataSource {
|
suspend fun insertOrUpdateRecentSearch(recentSearch: RecentSearch) {
|
||||||
private static final String TAG = RecentSearchDataSource.class.getSimpleName();
|
if (recentSearch.id != 0) {
|
||||||
|
recentSearchDao.updateRecentSearch(recentSearch)
|
||||||
private static RecentSearchDataSource INSTANCE;
|
return
|
||||||
|
}
|
||||||
private final RecentSearchDao recentSearchDao;
|
recentSearchDao.insertRecentSearch(recentSearch)
|
||||||
|
|
||||||
private RecentSearchDataSource(final RecentSearchDao recentSearchDao) {
|
|
||||||
this.recentSearchDao = recentSearchDao;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static synchronized RecentSearchDataSource getInstance(@NonNull Context context) {
|
suspend fun deleteRecentSearch(recentSearch: RecentSearch) = recentSearchDao.deleteRecentSearch(recentSearch)
|
||||||
if (INSTANCE == null) {
|
|
||||||
synchronized (RecentSearchDataSource.class) {
|
companion object {
|
||||||
if (INSTANCE == null) {
|
private lateinit var INSTANCE: RecentSearchDataSource
|
||||||
final AppDatabase database = AppDatabase.getDatabase(context);
|
|
||||||
INSTANCE = new RecentSearchDataSource(database.recentSearchDao());
|
@JvmStatic
|
||||||
|
@Synchronized
|
||||||
|
fun getInstance(context: Context): RecentSearchDataSource {
|
||||||
|
if (!this::INSTANCE.isInitialized) {
|
||||||
|
synchronized(RecentSearchDataSource::class.java) {
|
||||||
|
if (!this::INSTANCE.isInitialized) {
|
||||||
|
val database = AppDatabase.getDatabase(context)
|
||||||
|
INSTANCE = RecentSearchDataSource(database.recentSearchDao())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return INSTANCE;
|
return INSTANCE
|
||||||
}
|
}
|
||||||
|
|
||||||
public RecentSearch getRecentSearchByIgIdAndType(@NonNull final String igId, @NonNull final FavoriteType type) {
|
|
||||||
return recentSearchDao.getRecentSearchByIgIdAndType(igId, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final List<RecentSearch> getAllRecentSearches() {
|
|
||||||
return recentSearchDao.getAllRecentSearches();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void insertOrUpdateRecentSearch(@NonNull final RecentSearch recentSearch) {
|
|
||||||
if (recentSearch.getId() != 0) {
|
|
||||||
recentSearchDao.updateRecentSearch(recentSearch);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
recentSearchDao.insertRecentSearch(recentSearch);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void deleteRecentSearch(@NonNull final RecentSearch recentSearch) {
|
|
||||||
recentSearchDao.deleteRecentSearch(recentSearch);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,124 +1,52 @@
|
|||||||
package awais.instagrabber.db.repositories;
|
package awais.instagrabber.db.repositories
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import awais.instagrabber.db.datasources.RecentSearchDataSource
|
||||||
|
import awais.instagrabber.db.entities.RecentSearch
|
||||||
|
import awais.instagrabber.models.enums.FavoriteType
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
class RecentSearchRepository private constructor(private val recentSearchDataSource: RecentSearchDataSource) {
|
||||||
import java.util.List;
|
suspend fun getRecentSearch(igId: String, type: FavoriteType): RecentSearch? = recentSearchDataSource.getRecentSearchByIgIdAndType(igId, type)
|
||||||
|
|
||||||
import awais.instagrabber.db.datasources.RecentSearchDataSource;
|
suspend fun getAllRecentSearches(): List<RecentSearch> = recentSearchDataSource.getAllRecentSearches()
|
||||||
import awais.instagrabber.db.entities.RecentSearch;
|
|
||||||
import awais.instagrabber.models.enums.FavoriteType;
|
|
||||||
import awais.instagrabber.utils.AppExecutors;
|
|
||||||
|
|
||||||
public class RecentSearchRepository {
|
suspend fun insertOrUpdateRecentSearch(recentSearch: RecentSearch) =
|
||||||
private static final String TAG = RecentSearchRepository.class.getSimpleName();
|
insertOrUpdateRecentSearch(recentSearch.igId, recentSearch.name, recentSearch.username, recentSearch.picUrl, recentSearch.type)
|
||||||
|
|
||||||
private static RecentSearchRepository instance;
|
private suspend fun insertOrUpdateRecentSearch(
|
||||||
|
igId: String,
|
||||||
private final AppExecutors appExecutors;
|
name: String,
|
||||||
private final RecentSearchDataSource recentSearchDataSource;
|
username: String?,
|
||||||
|
picUrl: String?,
|
||||||
private RecentSearchRepository(final AppExecutors appExecutors, final RecentSearchDataSource recentSearchDataSource) {
|
type: FavoriteType,
|
||||||
this.appExecutors = appExecutors;
|
) {
|
||||||
this.recentSearchDataSource = recentSearchDataSource;
|
var recentSearch = recentSearchDataSource.getRecentSearchByIgIdAndType(igId, type)
|
||||||
|
recentSearch = if (recentSearch == null) {
|
||||||
|
RecentSearch(igId, name, username, picUrl, type, LocalDateTime.now())
|
||||||
|
} else {
|
||||||
|
RecentSearch(recentSearch.id, igId, name, username, picUrl, type, LocalDateTime.now())
|
||||||
|
}
|
||||||
|
recentSearchDataSource.insertOrUpdateRecentSearch(recentSearch)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RecentSearchRepository getInstance(final RecentSearchDataSource recentSearchDataSource) {
|
suspend fun deleteRecentSearchByIgIdAndType(igId: String, type: FavoriteType) {
|
||||||
if (instance == null) {
|
val recentSearch = recentSearchDataSource.getRecentSearchByIgIdAndType(igId, type)
|
||||||
instance = new RecentSearchRepository(AppExecutors.INSTANCE, recentSearchDataSource);
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void getRecentSearch(@NonNull final String igId,
|
|
||||||
@NonNull final FavoriteType type,
|
|
||||||
final RepositoryCallback<RecentSearch> callback) {
|
|
||||||
// request on the I/O thread
|
|
||||||
appExecutors.getDiskIO().execute(() -> {
|
|
||||||
final RecentSearch recentSearch = recentSearchDataSource.getRecentSearchByIgIdAndType(igId, type);
|
|
||||||
// notify on the main thread
|
|
||||||
appExecutors.getMainThread().execute(() -> {
|
|
||||||
if (callback == null) return;
|
|
||||||
if (recentSearch == null) {
|
|
||||||
callback.onDataNotAvailable();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
callback.onSuccess(recentSearch);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void getAllRecentSearches(final RepositoryCallback<List<RecentSearch>> callback) {
|
|
||||||
// request on the I/O thread
|
|
||||||
appExecutors.getDiskIO().execute(() -> {
|
|
||||||
final List<RecentSearch> recentSearches = recentSearchDataSource.getAllRecentSearches();
|
|
||||||
// notify on the main thread
|
|
||||||
appExecutors.getMainThread().execute(() -> {
|
|
||||||
if (callback == null) return;
|
|
||||||
callback.onSuccess(recentSearches);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void insertOrUpdateRecentSearch(@NonNull final RecentSearch recentSearch,
|
|
||||||
final RepositoryCallback<Void> callback) {
|
|
||||||
insertOrUpdateRecentSearch(recentSearch.getIgId(), recentSearch.getName(), recentSearch.getUsername(), recentSearch.getPicUrl(),
|
|
||||||
recentSearch.getType(), callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void insertOrUpdateRecentSearch(@NonNull final String igId,
|
|
||||||
@NonNull final String name,
|
|
||||||
final String username,
|
|
||||||
final String picUrl,
|
|
||||||
@NonNull final FavoriteType type,
|
|
||||||
final RepositoryCallback<Void> callback) {
|
|
||||||
// request on the I/O thread
|
|
||||||
appExecutors.getDiskIO().execute(() -> {
|
|
||||||
RecentSearch recentSearch = recentSearchDataSource.getRecentSearchByIgIdAndType(igId, type);
|
|
||||||
recentSearch = recentSearch == null
|
|
||||||
? new RecentSearch(igId, name, username, picUrl, type, LocalDateTime.now())
|
|
||||||
: new RecentSearch(recentSearch.getId(), igId, name, username, picUrl, type, LocalDateTime.now());
|
|
||||||
recentSearchDataSource.insertOrUpdateRecentSearch(recentSearch);
|
|
||||||
// notify on the main thread
|
|
||||||
appExecutors.getMainThread().execute(() -> {
|
|
||||||
if (callback == null) return;
|
|
||||||
callback.onSuccess(null);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deleteRecentSearchByIgIdAndType(@NonNull final String igId,
|
|
||||||
@NonNull final FavoriteType type,
|
|
||||||
final RepositoryCallback<Void> callback) {
|
|
||||||
// request on the I/O thread
|
|
||||||
appExecutors.getDiskIO().execute(() -> {
|
|
||||||
final RecentSearch recentSearch = recentSearchDataSource.getRecentSearchByIgIdAndType(igId, type);
|
|
||||||
if (recentSearch != null) {
|
if (recentSearch != null) {
|
||||||
recentSearchDataSource.deleteRecentSearch(recentSearch);
|
recentSearchDataSource.deleteRecentSearch(recentSearch)
|
||||||
}
|
}
|
||||||
// notify on the main thread
|
|
||||||
appExecutors.getMainThread().execute(() -> {
|
|
||||||
if (callback == null) return;
|
|
||||||
if (recentSearch == null) {
|
|
||||||
callback.onDataNotAvailable();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
callback.onSuccess(null);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteRecentSearch(@NonNull final RecentSearch recentSearch,
|
suspend fun deleteRecentSearch(recentSearch: RecentSearch) = recentSearchDataSource.deleteRecentSearch(recentSearch)
|
||||||
final RepositoryCallback<Void> callback) {
|
|
||||||
// request on the I/O thread
|
|
||||||
appExecutors.getDiskIO().execute(() -> {
|
|
||||||
|
|
||||||
recentSearchDataSource.deleteRecentSearch(recentSearch);
|
companion object {
|
||||||
// notify on the main thread
|
private lateinit var instance: RecentSearchRepository
|
||||||
appExecutors.getMainThread().execute(() -> {
|
|
||||||
if (callback == null) return;
|
@JvmStatic
|
||||||
callback.onSuccess(null);
|
fun getInstance(recentSearchDataSource: RecentSearchDataSource): RecentSearchRepository {
|
||||||
});
|
if (!this::instance.isInitialized) {
|
||||||
});
|
instance = RecentSearchRepository(recentSearchDataSource)
|
||||||
|
}
|
||||||
|
return instance
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,10 +1,12 @@
|
|||||||
package awais.instagrabber.repositories.responses.search
|
package awais.instagrabber.repositories.responses.search
|
||||||
|
|
||||||
class SearchResponse(// app
|
data class SearchResponse(
|
||||||
val list: List<SearchItem>,
|
// app
|
||||||
|
val list: List<SearchItem>?,
|
||||||
// browser
|
// browser
|
||||||
val users: List<SearchItem>,
|
val users: List<SearchItem>?,
|
||||||
val places: List<SearchItem>,
|
val places: List<SearchItem>?,
|
||||||
val hashtags: List<SearchItem>,
|
val hashtags: List<SearchItem>?,
|
||||||
// universal
|
// universal
|
||||||
val status: String)
|
val status: String?,
|
||||||
|
)
|
@ -25,7 +25,6 @@ import awais.instagrabber.db.entities.Favorite;
|
|||||||
import awais.instagrabber.db.entities.RecentSearch;
|
import awais.instagrabber.db.entities.RecentSearch;
|
||||||
import awais.instagrabber.db.repositories.FavoriteRepository;
|
import awais.instagrabber.db.repositories.FavoriteRepository;
|
||||||
import awais.instagrabber.db.repositories.RecentSearchRepository;
|
import awais.instagrabber.db.repositories.RecentSearchRepository;
|
||||||
import awais.instagrabber.db.repositories.RepositoryCallback;
|
|
||||||
import awais.instagrabber.models.Resource;
|
import awais.instagrabber.models.Resource;
|
||||||
import awais.instagrabber.models.enums.FavoriteType;
|
import awais.instagrabber.models.enums.FavoriteType;
|
||||||
import awais.instagrabber.repositories.responses.search.SearchItem;
|
import awais.instagrabber.repositories.responses.search.SearchItem;
|
||||||
@ -182,17 +181,17 @@ public class SearchFragmentViewModel extends AppStateViewModel {
|
|||||||
private void showRecentSearchesAndFavorites() {
|
private void showRecentSearchesAndFavorites() {
|
||||||
final SettableFuture<List<RecentSearch>> recentResultsFuture = SettableFuture.create();
|
final SettableFuture<List<RecentSearch>> recentResultsFuture = SettableFuture.create();
|
||||||
final SettableFuture<List<Favorite>> favoritesFuture = SettableFuture.create();
|
final SettableFuture<List<Favorite>> favoritesFuture = SettableFuture.create();
|
||||||
recentSearchRepository.getAllRecentSearches(new RepositoryCallback<List<RecentSearch>>() {
|
recentSearchRepository.getAllRecentSearches(
|
||||||
@Override
|
CoroutineUtilsKt.getContinuation((recentSearches, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
public void onSuccess(final List<RecentSearch> result) {
|
if (throwable != null) {
|
||||||
recentResultsFuture.set(result);
|
Log.e(TAG, "showRecentSearchesAndFavorites: ", throwable);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDataNotAvailable() {
|
|
||||||
recentResultsFuture.set(Collections.emptyList());
|
recentResultsFuture.set(Collections.emptyList());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
//noinspection unchecked
|
||||||
|
recentResultsFuture.set((List<RecentSearch>) recentSearches);
|
||||||
|
}), Dispatchers.getIO())
|
||||||
|
);
|
||||||
favoriteRepository.getAllFavorites(
|
favoriteRepository.getAllFavorites(
|
||||||
CoroutineUtilsKt.getContinuation((favorites, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
CoroutineUtilsKt.getContinuation((favorites, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
@ -290,9 +289,9 @@ public class SearchFragmentViewModel extends AppStateViewModel {
|
|||||||
case TOP:
|
case TOP:
|
||||||
list = ImmutableList
|
list = ImmutableList
|
||||||
.<SearchItem>builder()
|
.<SearchItem>builder()
|
||||||
.addAll(body.getUsers())
|
.addAll(body.getUsers() == null ? Collections.emptyList() : body.getUsers())
|
||||||
.addAll(body.getHashtags())
|
.addAll(body.getHashtags() == null ? Collections.emptyList() : body.getHashtags())
|
||||||
.addAll(body.getPlaces())
|
.addAll(body.getPlaces() == null ? Collections.emptyList() : body.getPlaces())
|
||||||
.build();
|
.build();
|
||||||
break;
|
break;
|
||||||
case USER:
|
case USER:
|
||||||
@ -315,15 +314,16 @@ public class SearchFragmentViewModel extends AppStateViewModel {
|
|||||||
try {
|
try {
|
||||||
final RecentSearch recentSearch = RecentSearch.fromSearchItem(searchItem);
|
final RecentSearch recentSearch = RecentSearch.fromSearchItem(searchItem);
|
||||||
if (recentSearch == null) return;
|
if (recentSearch == null) return;
|
||||||
recentSearchRepository.insertOrUpdateRecentSearch(recentSearch, new RepositoryCallback<Void>() {
|
recentSearchRepository.insertOrUpdateRecentSearch(
|
||||||
@Override
|
recentSearch,
|
||||||
public void onSuccess(final Void result) {
|
CoroutineUtilsKt.getContinuation((unit, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
// Log.d(TAG, "onSuccess: inserted recent: " + recentSearch);
|
if (throwable != null) {
|
||||||
|
Log.e(TAG, "saveToRecentSearches: ", throwable);
|
||||||
|
// return;
|
||||||
}
|
}
|
||||||
|
// Log.d(TAG, "onSuccess: inserted recent: " + recentSearch);
|
||||||
@Override
|
}), Dispatchers.getIO())
|
||||||
public void onDataNotAvailable() {}
|
);
|
||||||
});
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(TAG, "saveToRecentSearches: ", e);
|
Log.e(TAG, "saveToRecentSearches: ", e);
|
||||||
}
|
}
|
||||||
@ -336,19 +336,18 @@ public class SearchFragmentViewModel extends AppStateViewModel {
|
|||||||
if (recentSearch == null) return null;
|
if (recentSearch == null) return null;
|
||||||
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
|
||||||
data.postValue(Resource.loading(null));
|
data.postValue(Resource.loading(null));
|
||||||
recentSearchRepository.deleteRecentSearchByIgIdAndType(recentSearch.getIgId(), recentSearch.getType(), new RepositoryCallback<Void>() {
|
recentSearchRepository.deleteRecentSearchByIgIdAndType(
|
||||||
@Override
|
recentSearch.getIgId(),
|
||||||
public void onSuccess(final Void result) {
|
recentSearch.getType(),
|
||||||
// Log.d(TAG, "onSuccess: deleted");
|
CoroutineUtilsKt.getContinuation((unit, throwable) -> AppExecutors.INSTANCE.getMainThread().execute(() -> {
|
||||||
data.postValue(Resource.success(new Object()));
|
if (throwable != null) {
|
||||||
}
|
Log.e(TAG, "deleteRecentSearch: ", throwable);
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDataNotAvailable() {
|
|
||||||
// Log.e(TAG, "onDataNotAvailable: not deleted");
|
|
||||||
data.postValue(Resource.error("Error deleting recent item", null));
|
data.postValue(Resource.error("Error deleting recent item", null));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
data.postValue(Resource.success(new Object()));
|
||||||
|
}), Dispatchers.getIO())
|
||||||
|
);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user