mirror of
https://github.com/KokaKiwi/BarInsta
synced 2024-11-22 06:37:30 +00:00
convert HighlightModel usages (as archives) to Story
This commit is contained in:
parent
f7ce2eeea2
commit
7ead5046d9
@ -9,19 +9,19 @@ import androidx.recyclerview.widget.ListAdapter;
|
|||||||
|
|
||||||
import awais.instagrabber.adapters.viewholder.StoryListViewHolder;
|
import awais.instagrabber.adapters.viewholder.StoryListViewHolder;
|
||||||
import awais.instagrabber.databinding.ItemNotificationBinding;
|
import awais.instagrabber.databinding.ItemNotificationBinding;
|
||||||
import awais.instagrabber.models.HighlightModel;
|
import awais.instagrabber.repositories.responses.stories.Story;
|
||||||
|
|
||||||
public final class HighlightStoriesListAdapter extends ListAdapter<HighlightModel, StoryListViewHolder> {
|
public final class HighlightStoriesListAdapter extends ListAdapter<Story, StoryListViewHolder> {
|
||||||
private final OnHighlightStoryClickListener listener;
|
private final OnHighlightStoryClickListener listener;
|
||||||
|
|
||||||
private static final DiffUtil.ItemCallback<HighlightModel> diffCallback = new DiffUtil.ItemCallback<HighlightModel>() {
|
private static final DiffUtil.ItemCallback<Story> diffCallback = new DiffUtil.ItemCallback<Story>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean areItemsTheSame(@NonNull final HighlightModel oldItem, @NonNull final HighlightModel newItem) {
|
public boolean areItemsTheSame(@NonNull final Story oldItem, @NonNull final Story newItem) {
|
||||||
return oldItem.getId().equals(newItem.getId());
|
return oldItem.getId().equals(newItem.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean areContentsTheSame(@NonNull final HighlightModel oldItem, @NonNull final HighlightModel newItem) {
|
public boolean areContentsTheSame(@NonNull final Story oldItem, @NonNull final Story newItem) {
|
||||||
return oldItem.getId().equals(newItem.getId());
|
return oldItem.getId().equals(newItem.getId());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -41,12 +41,12 @@ public final class HighlightStoriesListAdapter extends ListAdapter<HighlightMode
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull final StoryListViewHolder holder, final int position) {
|
public void onBindViewHolder(@NonNull final StoryListViewHolder holder, final int position) {
|
||||||
final HighlightModel model = getItem(position);
|
final Story model = getItem(position);
|
||||||
holder.bind(model, position, listener);
|
holder.bind(model, position, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface OnHighlightStoryClickListener {
|
public interface OnHighlightStoryClickListener {
|
||||||
void onHighlightClick(final HighlightModel model, final int position);
|
void onHighlightClick(final Story model, final int position);
|
||||||
|
|
||||||
void onProfileClick(final String username);
|
void onProfileClick(final String username);
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import awais.instagrabber.R;
|
|||||||
import awais.instagrabber.adapters.FeedStoriesListAdapter.OnFeedStoryClickListener;
|
import awais.instagrabber.adapters.FeedStoriesListAdapter.OnFeedStoryClickListener;
|
||||||
import awais.instagrabber.adapters.HighlightStoriesListAdapter.OnHighlightStoryClickListener;
|
import awais.instagrabber.adapters.HighlightStoriesListAdapter.OnHighlightStoryClickListener;
|
||||||
import awais.instagrabber.databinding.ItemNotificationBinding;
|
import awais.instagrabber.databinding.ItemNotificationBinding;
|
||||||
import awais.instagrabber.models.HighlightModel;
|
|
||||||
import awais.instagrabber.repositories.responses.stories.Story;
|
import awais.instagrabber.repositories.responses.stories.Story;
|
||||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||||
|
|
||||||
@ -58,7 +57,7 @@ public final class StoryListViewHolder extends RecyclerView.ViewHolder {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bind(final HighlightModel model,
|
public void bind(final Story model,
|
||||||
final int position,
|
final int position,
|
||||||
final OnHighlightStoryClickListener notificationClickListener) {
|
final OnHighlightStoryClickListener notificationClickListener) {
|
||||||
if (model == null) return;
|
if (model == null) return;
|
||||||
@ -74,7 +73,7 @@ public final class StoryListViewHolder extends RecyclerView.ViewHolder {
|
|||||||
binding.ivProfilePic.setVisibility(View.GONE);
|
binding.ivProfilePic.setVisibility(View.GONE);
|
||||||
|
|
||||||
binding.ivPreviewPic.setVisibility(View.VISIBLE);
|
binding.ivPreviewPic.setVisibility(View.VISIBLE);
|
||||||
binding.ivPreviewPic.setImageURI(model.getThumbnailUrl());
|
binding.ivPreviewPic.setImageURI(model.getCoverImageVersion().getUrl());
|
||||||
|
|
||||||
itemView.setOnClickListener(v -> {
|
itemView.setOnClickListener(v -> {
|
||||||
if (notificationClickListener == null) return;
|
if (notificationClickListener == null) return;
|
||||||
|
@ -38,8 +38,8 @@ import awais.instagrabber.adapters.HighlightStoriesListAdapter.OnHighlightStoryC
|
|||||||
import awais.instagrabber.customviews.helpers.RecyclerLazyLoader;
|
import awais.instagrabber.customviews.helpers.RecyclerLazyLoader;
|
||||||
import awais.instagrabber.databinding.FragmentStoryListViewerBinding;
|
import awais.instagrabber.databinding.FragmentStoryListViewerBinding;
|
||||||
import awais.instagrabber.fragments.settings.MorePreferencesFragmentDirections;
|
import awais.instagrabber.fragments.settings.MorePreferencesFragmentDirections;
|
||||||
import awais.instagrabber.models.HighlightModel;
|
|
||||||
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
||||||
|
import awais.instagrabber.repositories.responses.stories.ArchiveResponse;
|
||||||
import awais.instagrabber.repositories.responses.stories.Story;
|
import awais.instagrabber.repositories.responses.stories.Story;
|
||||||
import awais.instagrabber.utils.AppExecutors;
|
import awais.instagrabber.utils.AppExecutors;
|
||||||
import awais.instagrabber.utils.CoroutineUtilsKt;
|
import awais.instagrabber.utils.CoroutineUtilsKt;
|
||||||
@ -48,7 +48,6 @@ import awais.instagrabber.viewmodels.ArchivesViewModel;
|
|||||||
import awais.instagrabber.viewmodels.FeedStoriesViewModel;
|
import awais.instagrabber.viewmodels.FeedStoriesViewModel;
|
||||||
import awais.instagrabber.webservices.ServiceCallback;
|
import awais.instagrabber.webservices.ServiceCallback;
|
||||||
import awais.instagrabber.webservices.StoriesRepository;
|
import awais.instagrabber.webservices.StoriesRepository;
|
||||||
import awais.instagrabber.webservices.StoriesRepository.ArchiveFetchResponse;
|
|
||||||
import kotlinx.coroutines.Dispatchers;
|
import kotlinx.coroutines.Dispatchers;
|
||||||
|
|
||||||
public final class StoryListViewerFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
|
public final class StoryListViewerFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
|
||||||
@ -88,7 +87,7 @@ public final class StoryListViewerFragment extends Fragment implements SwipeRefr
|
|||||||
|
|
||||||
private final OnHighlightStoryClickListener archiveClickListener = new OnHighlightStoryClickListener() {
|
private final OnHighlightStoryClickListener archiveClickListener = new OnHighlightStoryClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onHighlightClick(final HighlightModel model, final int position) {
|
public void onHighlightClick(final Story model, final int position) {
|
||||||
if (model == null) return;
|
if (model == null) return;
|
||||||
final NavDirections action = StoryListViewerFragmentDirections
|
final NavDirections action = StoryListViewerFragmentDirections
|
||||||
.actionStoryListFragmentToStoryViewerFragment(StoryViewerOptions.forStoryArchive(position));
|
.actionStoryListFragmentToStoryViewerFragment(StoryViewerOptions.forStoryArchive(position));
|
||||||
@ -101,9 +100,9 @@ public final class StoryListViewerFragment extends Fragment implements SwipeRefr
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final ServiceCallback<ArchiveFetchResponse> cb = new ServiceCallback<ArchiveFetchResponse>() {
|
private final ServiceCallback<ArchiveResponse> cb = new ServiceCallback<ArchiveResponse>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(final ArchiveFetchResponse result) {
|
public void onSuccess(final ArchiveResponse result) {
|
||||||
binding.swipeRefreshLayout.setRefreshing(false);
|
binding.swipeRefreshLayout.setRefreshing(false);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
try {
|
try {
|
||||||
@ -111,10 +110,10 @@ public final class StoryListViewerFragment extends Fragment implements SwipeRefr
|
|||||||
Toast.makeText(context, R.string.empty_list, Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, R.string.empty_list, Toast.LENGTH_SHORT).show();
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
} else {
|
} else {
|
||||||
endCursor = result.getNextCursor();
|
endCursor = result.getMaxId();
|
||||||
final List<HighlightModel> models = archivesViewModel.getList().getValue();
|
final List<Story> models = archivesViewModel.getList().getValue();
|
||||||
final List<HighlightModel> modelsCopy = models == null ? new ArrayList<>() : new ArrayList<>(models);
|
final List<Story> modelsCopy = models == null ? new ArrayList<>() : new ArrayList<>(models);
|
||||||
modelsCopy.addAll(result.getResult());
|
modelsCopy.addAll(result.getItems());
|
||||||
archivesViewModel.getList().postValue(modelsCopy);
|
archivesViewModel.getList().postValue(modelsCopy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,6 @@ import awais.instagrabber.databinding.FragmentStoryViewerBinding;
|
|||||||
import awais.instagrabber.fragments.main.ProfileFragmentDirections;
|
import awais.instagrabber.fragments.main.ProfileFragmentDirections;
|
||||||
import awais.instagrabber.fragments.settings.PreferenceKeys;
|
import awais.instagrabber.fragments.settings.PreferenceKeys;
|
||||||
import awais.instagrabber.interfaces.SwipeEvent;
|
import awais.instagrabber.interfaces.SwipeEvent;
|
||||||
import awais.instagrabber.models.HighlightModel;
|
|
||||||
import awais.instagrabber.models.StoryModel;
|
import awais.instagrabber.models.StoryModel;
|
||||||
import awais.instagrabber.models.enums.MediaItemType;
|
import awais.instagrabber.models.enums.MediaItemType;
|
||||||
import awais.instagrabber.models.stickers.PollModel;
|
import awais.instagrabber.models.stickers.PollModel;
|
||||||
@ -760,12 +759,12 @@ public class StoryViewerFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
case STORY_ARCHIVE: {
|
case STORY_ARCHIVE: {
|
||||||
final ArchivesViewModel archivesViewModel = (ArchivesViewModel) viewModel;
|
final ArchivesViewModel archivesViewModel = (ArchivesViewModel) viewModel;
|
||||||
final List<HighlightModel> models = archivesViewModel.getList().getValue();
|
final List<Story> models = archivesViewModel.getList().getValue();
|
||||||
if (models == null || models.isEmpty() || currentFeedStoryIndex >= models.size() || currentFeedStoryIndex < 0) {
|
if (models == null || models.isEmpty() || currentFeedStoryIndex >= models.size() || currentFeedStoryIndex < 0) {
|
||||||
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final HighlightModel model = models.get(currentFeedStoryIndex);
|
final Story model = models.get(currentFeedStoryIndex);
|
||||||
currentStoryMediaId = parseStoryMediaId(model.getId());
|
currentStoryMediaId = parseStoryMediaId(model.getId());
|
||||||
currentStoryUsername = model.getTitle();
|
currentStoryUsername = model.getTitle();
|
||||||
fetchOptions = StoryViewerOptions.forStoryArchive(model.getId());
|
fetchOptions = StoryViewerOptions.forStoryArchive(model.getId());
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
package awais.instagrabber.models
|
|
||||||
|
|
||||||
import awais.instagrabber.utils.TextUtils
|
|
||||||
|
|
||||||
data class HighlightModel(
|
|
||||||
val title: String? = null,
|
|
||||||
val id: String = "",
|
|
||||||
val thumbnailUrl: String = "",
|
|
||||||
val timestamp: Long = 0,
|
|
||||||
val mediaCount: Int = 0,
|
|
||||||
) {
|
|
||||||
val dateTime: String
|
|
||||||
get() = TextUtils.epochSecondToString(timestamp)
|
|
||||||
}
|
|
@ -1,5 +1,6 @@
|
|||||||
package awais.instagrabber.repositories
|
package awais.instagrabber.repositories
|
||||||
|
|
||||||
|
import awais.instagrabber.repositories.responses.stories.ArchiveResponse
|
||||||
import awais.instagrabber.repositories.responses.stories.ReelsTrayResponse
|
import awais.instagrabber.repositories.responses.stories.ReelsTrayResponse
|
||||||
import awais.instagrabber.repositories.responses.stories.StoryStickerResponse
|
import awais.instagrabber.repositories.responses.stories.StoryStickerResponse
|
||||||
import retrofit2.http.*
|
import retrofit2.http.*
|
||||||
@ -16,7 +17,7 @@ interface StoriesService {
|
|||||||
suspend fun fetchHighlights(@Path("uid") uid: Long): ReelsTrayResponse
|
suspend fun fetchHighlights(@Path("uid") uid: Long): ReelsTrayResponse
|
||||||
|
|
||||||
@GET("/api/v1/archive/reel/day_shells/")
|
@GET("/api/v1/archive/reel/day_shells/")
|
||||||
suspend fun fetchArchive(@QueryMap queryParams: Map<String, String>): String
|
suspend fun fetchArchive(@QueryMap queryParams: Map<String, String>): ArchiveResponse?
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
suspend fun getUserStory(@Url url: String): String
|
suspend fun getUserStory(@Url url: String): String
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
package awais.instagrabber.repositories.responses.stories
|
||||||
|
|
||||||
|
data class ArchiveResponse(
|
||||||
|
val numResults: Int,
|
||||||
|
val maxId: String?,
|
||||||
|
val moreAvailable: Boolean,
|
||||||
|
val status: String,
|
||||||
|
val items: List<Story>
|
||||||
|
)
|
@ -1,6 +1,7 @@
|
|||||||
package awais.instagrabber.repositories.responses.stories
|
package awais.instagrabber.repositories.responses.stories
|
||||||
|
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
import awais.instagrabber.repositories.responses.ImageUrl
|
||||||
import awais.instagrabber.repositories.responses.User
|
import awais.instagrabber.repositories.responses.User
|
||||||
import awais.instagrabber.utils.TextUtils
|
import awais.instagrabber.utils.TextUtils
|
||||||
|
|
||||||
@ -8,19 +9,23 @@ data class Story(
|
|||||||
// universal
|
// universal
|
||||||
val id: String?,
|
val id: String?,
|
||||||
val latestReelMedia: Long?, // = timestamp
|
val latestReelMedia: Long?, // = timestamp
|
||||||
|
val mediaCount: Int?,
|
||||||
|
// for stories and highlights
|
||||||
var seen: Long?,
|
var seen: Long?,
|
||||||
val user: User?,
|
val user: User?,
|
||||||
// for stories
|
// for stories
|
||||||
val mediaCount: Int?,
|
|
||||||
val muted: Boolean?,
|
val muted: Boolean?,
|
||||||
val hasBestiesMedia: Boolean?,
|
val hasBestiesMedia: Boolean?,
|
||||||
val items: List<StoryMedia>?, // may be null
|
val items: List<StoryMedia>?, // may be null
|
||||||
// for highlights
|
// for highlights
|
||||||
val coverMedia: CoverMedia?,
|
val coverMedia: CoverMedia?,
|
||||||
val title: String?,
|
val title: String?,
|
||||||
|
// for archives
|
||||||
|
val coverImageVersion: ImageUrl?,
|
||||||
// invented fields
|
// invented fields
|
||||||
val broadcast: Broadcast? // does not naturally occur
|
val broadcast: Broadcast? // does not naturally occur
|
||||||
) : Serializable {
|
) : Serializable {
|
||||||
val dateTime: String
|
val dateTime: String
|
||||||
get() = if (latestReelMedia != null) TextUtils.epochSecondToString(latestReelMedia) else ""
|
get() = if (latestReelMedia != null) TextUtils.epochSecondToString(latestReelMedia) else ""
|
||||||
|
// note that archives have property "timestamp" but is ignored
|
||||||
}
|
}
|
@ -5,12 +5,12 @@ import androidx.lifecycle.ViewModel;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import awais.instagrabber.models.HighlightModel;
|
import awais.instagrabber.repositories.responses.stories.Story;
|
||||||
|
|
||||||
public class ArchivesViewModel extends ViewModel {
|
public class ArchivesViewModel extends ViewModel {
|
||||||
private MutableLiveData<List<HighlightModel>> list;
|
private MutableLiveData<List<Story>> list;
|
||||||
|
|
||||||
public MutableLiveData<List<HighlightModel>> getList() {
|
public MutableLiveData<List<Story>> getList() {
|
||||||
if (list == null) {
|
if (list == null) {
|
||||||
list = new MutableLiveData<>();
|
list = new MutableLiveData<>();
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package awais.instagrabber.webservices
|
package awais.instagrabber.webservices
|
||||||
|
|
||||||
import awais.instagrabber.fragments.settings.PreferenceKeys
|
import awais.instagrabber.fragments.settings.PreferenceKeys
|
||||||
import awais.instagrabber.models.HighlightModel
|
|
||||||
import awais.instagrabber.models.StoryModel
|
import awais.instagrabber.models.StoryModel
|
||||||
import awais.instagrabber.repositories.StoriesService
|
import awais.instagrabber.repositories.StoriesService
|
||||||
import awais.instagrabber.repositories.requests.StoryViewerOptions
|
import awais.instagrabber.repositories.requests.StoryViewerOptions
|
||||||
|
import awais.instagrabber.repositories.responses.stories.ArchiveResponse
|
||||||
import awais.instagrabber.repositories.responses.stories.Story
|
import awais.instagrabber.repositories.responses.stories.Story
|
||||||
import awais.instagrabber.repositories.responses.stories.StoryStickerResponse
|
import awais.instagrabber.repositories.responses.stories.StoryStickerResponse
|
||||||
import awais.instagrabber.utils.Constants
|
import awais.instagrabber.utils.Constants
|
||||||
@ -35,14 +35,15 @@ open class StoriesRepository(private val service: StoriesService) {
|
|||||||
Story(
|
Story(
|
||||||
broadcast.id,
|
broadcast.id,
|
||||||
broadcast.publishedTime,
|
broadcast.publishedTime,
|
||||||
|
1,
|
||||||
0L,
|
0L,
|
||||||
broadcast.broadcastOwner,
|
broadcast.broadcastOwner,
|
||||||
1,
|
|
||||||
broadcast.muted,
|
broadcast.muted,
|
||||||
false, // unclear
|
false, // unclear
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
null,
|
||||||
broadcast
|
broadcast
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -53,11 +54,11 @@ open class StoriesRepository(private val service: StoriesService) {
|
|||||||
|
|
||||||
open suspend fun fetchHighlights(profileId: Long): List<Story> {
|
open suspend fun fetchHighlights(profileId: Long): List<Story> {
|
||||||
val response = service.fetchHighlights(profileId)
|
val response = service.fetchHighlights(profileId)
|
||||||
val highlightModels = response.tray ?: listOf()
|
val highlightModels = response?.tray ?: listOf()
|
||||||
return highlightModels
|
return highlightModels
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun fetchArchive(maxId: String): ArchiveFetchResponse {
|
suspend fun fetchArchive(maxId: String): ArchiveResponse? {
|
||||||
val form = mutableMapOf(
|
val form = mutableMapOf(
|
||||||
"include_suggested_highlights" to "false",
|
"include_suggested_highlights" to "false",
|
||||||
"is_in_archive_home" to "true",
|
"is_in_archive_home" to "true",
|
||||||
@ -66,24 +67,7 @@ open class StoriesRepository(private val service: StoriesService) {
|
|||||||
if (!isEmpty(maxId)) {
|
if (!isEmpty(maxId)) {
|
||||||
form["max_id"] = maxId // NOT TESTED
|
form["max_id"] = maxId // NOT TESTED
|
||||||
}
|
}
|
||||||
val response = service.fetchArchive(form)
|
return service.fetchArchive(form)
|
||||||
val data = JSONObject(response)
|
|
||||||
val highlightsReel = data.getJSONArray("items")
|
|
||||||
val length = highlightsReel.length()
|
|
||||||
val highlightModels: MutableList<HighlightModel> = ArrayList()
|
|
||||||
for (i in 0 until length) {
|
|
||||||
val highlightNode = highlightsReel.getJSONObject(i)
|
|
||||||
highlightModels.add(
|
|
||||||
HighlightModel(
|
|
||||||
null,
|
|
||||||
highlightNode.getString(Constants.EXTRAS_ID),
|
|
||||||
highlightNode.getJSONObject("cover_image_version").getString("url"),
|
|
||||||
highlightNode.getLong("latest_reel_media"),
|
|
||||||
highlightNode.getInt("media_count")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return ArchiveFetchResponse(highlightModels, data.getBoolean("more_available"), data.getString("max_id"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open suspend fun getUserStory(options: StoryViewerOptions): List<StoryModel> {
|
open suspend fun getUserStory(options: StoryViewerOptions): List<StoryModel> {
|
||||||
@ -248,12 +232,6 @@ open class StoriesRepository(private val service: StoriesService) {
|
|||||||
return listCopy
|
return listCopy
|
||||||
}
|
}
|
||||||
|
|
||||||
class ArchiveFetchResponse(val result: List<HighlightModel>, val hasNextPage: Boolean, val nextCursor: String) {
|
|
||||||
fun hasNextPage(): Boolean {
|
|
||||||
return hasNextPage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@Volatile
|
@Volatile
|
||||||
private var INSTANCE: StoriesRepository? = null
|
private var INSTANCE: StoriesRepository? = null
|
||||||
|
Loading…
Reference in New Issue
Block a user