Skip to content

Commit 4588897

Browse files
authored
Merge pull request #16 from tmaxxdd/feature/filter-snippets-by-language
Handled filtering snippets by language
2 parents 24db106 + ea6a0a8 commit 4588897

File tree

16 files changed

+265
-143
lines changed

16 files changed

+265
-143
lines changed

app/src/main/java/pl/tkadziolka/snipmeandroid/bridge/Bridge.java

Lines changed: 59 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,21 @@
44
package pl.tkadziolka.snipmeandroid.bridge;
55

66
import android.util.Log;
7+
78
import androidx.annotation.NonNull;
89
import androidx.annotation.Nullable;
9-
import io.flutter.plugin.common.BasicMessageChannel;
10-
import io.flutter.plugin.common.BinaryMessenger;
11-
import io.flutter.plugin.common.MessageCodec;
12-
import io.flutter.plugin.common.StandardMessageCodec;
10+
1311
import java.io.ByteArrayOutputStream;
1412
import java.nio.ByteBuffer;
15-
import java.util.Arrays;
1613
import java.util.ArrayList;
17-
import java.util.Collections;
14+
import java.util.HashMap;
1815
import java.util.List;
1916
import java.util.Map;
20-
import java.util.HashMap;
17+
18+
import io.flutter.plugin.common.BasicMessageChannel;
19+
import io.flutter.plugin.common.BinaryMessenger;
20+
import io.flutter.plugin.common.MessageCodec;
21+
import io.flutter.plugin.common.StandardMessageCodec;
2122

2223
/**Generated class from Pigeon. */
2324
@SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression"})
@@ -562,33 +563,48 @@ public static final class Builder {
562563

563564
/** Generated class from Pigeon that represents data sent in messages. */
564565
public static class SnippetFilter {
565-
private @Nullable SnippetFilterType type;
566-
public @Nullable SnippetFilterType getType() { return type; }
567-
public void setType(@Nullable SnippetFilterType setterArg) {
568-
this.type = setterArg;
566+
private @Nullable List<String> languages;
567+
public @Nullable List<String> getLanguages() { return languages; }
568+
public void setLanguages(@Nullable List<String> setterArg) {
569+
this.languages = setterArg;
570+
}
571+
572+
private @Nullable List<String> selectedLanguages;
573+
public @Nullable List<String> getSelectedLanguages() { return selectedLanguages; }
574+
public void setSelectedLanguages(@Nullable List<String> setterArg) {
575+
this.selectedLanguages = setterArg;
569576
}
570577

571578
public static final class Builder {
572-
private @Nullable SnippetFilterType type;
573-
public @NonNull Builder setType(@Nullable SnippetFilterType setterArg) {
574-
this.type = setterArg;
579+
private @Nullable List<String> languages;
580+
public @NonNull Builder setLanguages(@Nullable List<String> setterArg) {
581+
this.languages = setterArg;
582+
return this;
583+
}
584+
private @Nullable List<String> selectedLanguages;
585+
public @NonNull Builder setSelectedLanguages(@Nullable List<String> setterArg) {
586+
this.selectedLanguages = setterArg;
575587
return this;
576588
}
577589
public @NonNull SnippetFilter build() {
578590
SnippetFilter pigeonReturn = new SnippetFilter();
579-
pigeonReturn.setType(type);
591+
pigeonReturn.setLanguages(languages);
592+
pigeonReturn.setSelectedLanguages(selectedLanguages);
580593
return pigeonReturn;
581594
}
582595
}
583596
@NonNull Map<String, Object> toMap() {
584597
Map<String, Object> toMapResult = new HashMap<>();
585-
toMapResult.put("type", type == null ? null : type.index);
598+
toMapResult.put("languages", languages);
599+
toMapResult.put("selectedLanguages", selectedLanguages);
586600
return toMapResult;
587601
}
588602
static @NonNull SnippetFilter fromMap(@NonNull Map<String, Object> map) {
589603
SnippetFilter pigeonResult = new SnippetFilter();
590-
Object type = map.get("type");
591-
pigeonResult.setType(type == null ? null : SnippetFilterType.values()[(int)type]);
604+
Object languages = map.get("languages");
605+
pigeonResult.setLanguages((List<String>)languages);
606+
Object selectedLanguages = map.get("selectedLanguages");
607+
pigeonResult.setSelectedLanguages((List<String>)selectedLanguages);
592608
return pigeonResult;
593609
}
594610
}
@@ -613,6 +629,12 @@ public void setData(@Nullable List<Snippet> setterArg) {
613629
this.data = setterArg;
614630
}
615631

632+
private @Nullable SnippetFilter filter;
633+
public @Nullable SnippetFilter getFilter() { return filter; }
634+
public void setFilter(@Nullable SnippetFilter setterArg) {
635+
this.filter = setterArg;
636+
}
637+
616638
private @Nullable String error;
617639
public @Nullable String getError() { return error; }
618640
public void setError(@Nullable String setterArg) {
@@ -647,6 +669,11 @@ public static final class Builder {
647669
this.data = setterArg;
648670
return this;
649671
}
672+
private @Nullable SnippetFilter filter;
673+
public @NonNull Builder setFilter(@Nullable SnippetFilter setterArg) {
674+
this.filter = setterArg;
675+
return this;
676+
}
650677
private @Nullable String error;
651678
public @NonNull Builder setError(@Nullable String setterArg) {
652679
this.error = setterArg;
@@ -667,6 +694,7 @@ public static final class Builder {
667694
pigeonReturn.setState(state);
668695
pigeonReturn.setIs_loading(is_loading);
669696
pigeonReturn.setData(data);
697+
pigeonReturn.setFilter(filter);
670698
pigeonReturn.setError(error);
671699
pigeonReturn.setOldHash(oldHash);
672700
pigeonReturn.setNewHash(newHash);
@@ -678,6 +706,7 @@ public static final class Builder {
678706
toMapResult.put("state", state == null ? null : state.index);
679707
toMapResult.put("is_loading", is_loading);
680708
toMapResult.put("data", data);
709+
toMapResult.put("filter", (filter == null) ? null : filter.toMap());
681710
toMapResult.put("error", error);
682711
toMapResult.put("oldHash", oldHash);
683712
toMapResult.put("newHash", newHash);
@@ -691,6 +720,8 @@ public static final class Builder {
691720
pigeonResult.setIs_loading((Boolean)is_loading);
692721
Object data = map.get("data");
693722
pigeonResult.setData((List<Snippet>)data);
723+
Object filter = map.get("filter");
724+
pigeonResult.setFilter((filter == null) ? null : SnippetFilter.fromMap((Map)filter));
694725
Object error = map.get("error");
695726
pigeonResult.setError((String)error);
696727
Object oldHash = map.get("oldHash");
@@ -1186,8 +1217,7 @@ public interface MainModelBridge {
11861217
@NonNull MainModelEventData getEvent();
11871218
void resetEvent();
11881219
void initState();
1189-
void loadNextPage();
1190-
void filter(@NonNull SnippetFilter filter);
1220+
void filterLanguage(@NonNull String language, @NonNull Boolean isSelected);
11911221
void logOut();
11921222
void refreshSnippetUpdates();
11931223

@@ -1276,38 +1306,22 @@ static void setup(BinaryMessenger binaryMessenger, MainModelBridge api) {
12761306
{
12771307
BinaryMessenger.TaskQueue taskQueue = binaryMessenger.makeBackgroundTaskQueue();
12781308
BasicMessageChannel<Object> channel =
1279-
new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.MainModelBridge.loadNextPage", getCodec(), taskQueue);
1280-
if (api != null) {
1281-
channel.setMessageHandler((message, reply) -> {
1282-
Map<String, Object> wrapped = new HashMap<>();
1283-
try {
1284-
api.loadNextPage();
1285-
wrapped.put("result", null);
1286-
}
1287-
catch (Error | RuntimeException exception) {
1288-
wrapped.put("error", wrapError(exception));
1289-
}
1290-
reply.reply(wrapped);
1291-
});
1292-
} else {
1293-
channel.setMessageHandler(null);
1294-
}
1295-
}
1296-
{
1297-
BinaryMessenger.TaskQueue taskQueue = binaryMessenger.makeBackgroundTaskQueue();
1298-
BasicMessageChannel<Object> channel =
1299-
new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.MainModelBridge.filter", getCodec(), taskQueue);
1309+
new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.MainModelBridge.filterLanguage", getCodec(), taskQueue);
13001310
if (api != null) {
13011311
channel.setMessageHandler((message, reply) -> {
13021312
Map<String, Object> wrapped = new HashMap<>();
13031313
try {
13041314
ArrayList<Object> args = (ArrayList<Object>)message;
13051315
assert args != null;
1306-
SnippetFilter filterArg = (SnippetFilter)args.get(0);
1307-
if (filterArg == null) {
1308-
throw new NullPointerException("filterArg unexpectedly null.");
1316+
String languageArg = (String)args.get(0);
1317+
if (languageArg == null) {
1318+
throw new NullPointerException("languageArg unexpectedly null.");
1319+
}
1320+
Boolean isSelectedArg = (Boolean)args.get(1);
1321+
if (isSelectedArg == null) {
1322+
throw new NullPointerException("isSelectedArg unexpectedly null.");
13091323
}
1310-
api.filter(filterArg);
1324+
api.filterLanguage(languageArg, isSelectedArg);
13111325
wrapped.put("result", null);
13121326
}
13131327
catch (Error | RuntimeException exception) {

app/src/main/java/pl/tkadziolka/snipmeandroid/bridge/main/MainModel.kt

Lines changed: 57 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ import io.reactivex.schedulers.Schedulers
77
import kotlinx.coroutines.flow.MutableStateFlow
88
import pl.tkadziolka.snipmeandroid.bridge.session.SessionModel
99
import pl.tkadziolka.snipmeandroid.domain.error.exception.*
10+
import pl.tkadziolka.snipmeandroid.domain.filter.FilterSnippetsByLanguageUseCase
11+
import pl.tkadziolka.snipmeandroid.domain.filter.GetLanguageFiltersUseCase
12+
import pl.tkadziolka.snipmeandroid.domain.filter.SNIPPET_LANGUAGE_FILTER_ALL
13+
import pl.tkadziolka.snipmeandroid.domain.filter.UpdateSnippetFiltersLanguageUseCase
1014
import pl.tkadziolka.snipmeandroid.domain.message.ErrorMessages
1115
import pl.tkadziolka.snipmeandroid.domain.snippet.ObserveUpdatedSnippetPageUseCase
1216
import pl.tkadziolka.snipmeandroid.domain.snippet.ResetUpdatedSnippetPageUseCase
13-
import pl.tkadziolka.snipmeandroid.domain.snippets.GetSnippetsUseCase
14-
import pl.tkadziolka.snipmeandroid.domain.snippets.HasMoreSnippetPagesUseCase
15-
import pl.tkadziolka.snipmeandroid.domain.snippets.SnippetScope
17+
import pl.tkadziolka.snipmeandroid.domain.snippets.*
1618
import pl.tkadziolka.snipmeandroid.domain.user.GetSingleUserUseCase
1719
import pl.tkadziolka.snipmeandroid.domain.user.User
1820
import pl.tkadziolka.snipmeandroid.ui.error.ErrorParsable
@@ -29,23 +31,36 @@ class MainModel(
2931
private val observeUpdatedPage: ObserveUpdatedSnippetPageUseCase,
3032
private val resetUpdatedPage: ResetUpdatedSnippetPageUseCase,
3133
private val hasMore: HasMoreSnippetPagesUseCase,
34+
private val getLanguageFilters: GetLanguageFiltersUseCase,
35+
private val filterSnippetsByLanguage: FilterSnippetsByLanguageUseCase,
36+
private val updateFilterLanguage: UpdateSnippetFiltersLanguageUseCase,
3237
private val session: SessionModel
3338
) : ErrorParsable {
3439
private val disposables = CompositeDisposable()
35-
private var shouldRefresh = false
3640

3741
private val mutableEvent = MutableStateFlow<MainEvent>(Startup)
3842
val event = mutableEvent
3943

4044
private val mutableState = MutableStateFlow<MainViewState>(Loading)
4145
val state = mutableState
4246

47+
private var cachedSnippets = emptyList<Snippet>()
48+
private var shouldRefresh = false
49+
private var filterState = SnippetFilters(
50+
languages = listOf(SNIPPET_LANGUAGE_FILTER_ALL),
51+
selectedLanguages = listOf(SNIPPET_LANGUAGE_FILTER_ALL),
52+
scope = SnippetScope.ALL
53+
)
54+
4355
override fun parseError(throwable: Throwable) {
4456
when (throwable) {
4557
is ConnectionException -> mutableState.value = Error(errorMessages.parse(throwable))
46-
is ContentNotFoundException -> mutableState.value = Error(errorMessages.parse(throwable))
47-
is ForbiddenActionException -> mutableState.value = Error(errorMessages.parse(throwable))
48-
is NetworkNotAvailableException -> mutableState.value = Error(errorMessages.parse(throwable))
58+
is ContentNotFoundException -> mutableState.value =
59+
Error(errorMessages.parse(throwable))
60+
is ForbiddenActionException -> mutableState.value =
61+
Error(errorMessages.parse(throwable))
62+
is NetworkNotAvailableException -> mutableState.value =
63+
Error(errorMessages.parse(throwable))
4964
is NotAuthorizedException -> session.logOut { mutableEvent.value = Logout }
5065
is RemoteException -> mutableState.value = Error(errorMessages.parse(throwable))
5166
is SessionExpiredException -> session.logOut { mutableEvent.value = Logout }
@@ -54,7 +69,7 @@ class MainModel(
5469
}
5570

5671
fun initState() {
57-
mutableState.value = (Loading)
72+
mutableState.value = Loading
5873
getUser()
5974
.subscribeOn(Schedulers.io())
6075
.subscribeBy(
@@ -66,23 +81,15 @@ class MainModel(
6681
).also { disposables += it }
6782
}
6883

69-
fun loadNextPage() {
70-
getLoadedState()?.let { state ->
71-
hasMore(state.scope, state.pages)
72-
.subscribeOn(Schedulers.io())
73-
.subscribeBy(
74-
onSuccess = { hasMore ->
75-
if (hasMore) loadSnippets(state.user, pages = state.pages + ONE_PAGE)
76-
},
77-
onError = {
78-
Timber.e("Couldn't check next page, error = $it")
79-
mutableEvent.value = Alert(errorMessages.parse(it))
80-
})
81-
.also { disposables += it }
84+
fun filterLanguage(language: String, isSelected: Boolean) {
85+
getLoadedState()?.let {
86+
filterState = updateFilterLanguage(filterState, language, isSelected)
87+
val filteredSnippets = filterSnippetsByLanguage(cachedSnippets, filterState.selectedLanguages)
88+
state.value = it.copy(snippets = filteredSnippets, filters = filterState)
8289
}
8390
}
8491

85-
fun filter(filter: SnippetFilter) {
92+
fun filterScope(filter: SnippetFilter) {
8693
val scope = filterToScope(filter)
8794
getLoadedState()?.let { state ->
8895
loadSnippets(state.user, pages = ONE_PAGE, scope = scope)
@@ -109,6 +116,24 @@ class MainModel(
109116
}
110117
}
111118

119+
private fun loadNextPage() {
120+
getLoadedState()?.let { state ->
121+
hasMore(state.filters.scope, state.pages)
122+
.subscribeOn(Schedulers.io())
123+
.subscribeBy(
124+
onSuccess = { hasMore ->
125+
if (hasMore) {
126+
loadSnippets(state.user, pages = state.pages + ONE_PAGE)
127+
}
128+
},
129+
onError = {
130+
Timber.e("Couldn't check next page, error = $it")
131+
mutableEvent.value = Alert(errorMessages.parse(it))
132+
})
133+
.also { disposables += it }
134+
}
135+
}
136+
112137
private fun loadSnippets(
113138
user: User,
114139
pages: Int = 1,
@@ -118,7 +143,15 @@ class MainModel(
118143
.subscribeOn(Schedulers.io())
119144
.subscribeBy(
120145
onSuccess = {
121-
mutableState.value = (Loaded(user, it, pages, scope))
146+
cachedSnippets = it
147+
val updatedFilters = getLanguageFilters(cachedSnippets)
148+
filterState = filterState.copy(languages = updatedFilters)
149+
mutableState.value = Loaded(
150+
user,
151+
it,
152+
pages,
153+
filterState
154+
)
122155
loadNextPage()
123156
if (shouldRefresh) {
124157
mutableEvent.value = ListRefreshed
@@ -143,7 +176,7 @@ class MainModel(
143176

144177
private fun getScope(): SnippetScope {
145178
getLoadedState()?.let {
146-
return it.scope
179+
return it.filters.scope
147180
}
148181
return SnippetScope.ALL
149182
}

app/src/main/java/pl/tkadziolka/snipmeandroid/bridge/main/MainModelPlugin.kt

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import pl.tkadziolka.snipmeandroid.bridge.Bridge
66
import pl.tkadziolka.snipmeandroid.bridge.ModelPlugin
77
import pl.tkadziolka.snipmeandroid.bridge.toModelData
88
import pl.tkadziolka.snipmeandroid.domain.snippets.Snippet
9+
import pl.tkadziolka.snipmeandroid.domain.snippets.SnippetFilters
910
import pl.tkadziolka.snipmeandroid.ui.main.*
1011
import pl.tkadziolka.snipmeandroid.util.view.SnippetFilter
1112

@@ -33,14 +34,8 @@ class MainModelPlugin : ModelPlugin<Bridge.MainModelBridge>(), Bridge.MainModelB
3334
model.initState()
3435
}
3536

36-
override fun loadNextPage() {
37-
model.loadNextPage()
38-
}
39-
40-
override fun filter(filter: Bridge.SnippetFilter) {
41-
val type = (filter.type?.name ?: Bridge.SnippetFilterType.ALL.name).uppercase()
42-
val snippetFilter = SnippetFilter.valueOf(type)
43-
model.filter(snippetFilter)
37+
override fun filterLanguage(language: String, isSelected: Boolean) {
38+
model.filterLanguage(language, isSelected)
4439
}
4540

4641
override fun logOut() {
@@ -56,6 +51,7 @@ class MainModelPlugin : ModelPlugin<Bridge.MainModelBridge>(), Bridge.MainModelB
5651
state = viewState.toModelState()
5752
is_loading = viewState is Loading
5853
data = (viewState as? Loaded)?.snippets?.toModelData()
54+
filter = (viewState as? Loaded)?.filters?.toModelFilter()
5955
oldHash = oldState?.hashCode()?.toLong()
6056
newHash = viewState.hashCode().toLong()
6157
}.also {
@@ -89,4 +85,12 @@ class MainModelPlugin : ModelPlugin<Bridge.MainModelBridge>(), Bridge.MainModelB
8985
}
9086

9187
private fun List<Snippet>.toModelData() = map { it.toModelData() }
88+
89+
private fun SnippetFilters.toModelFilter(): Bridge.SnippetFilter {
90+
val it = this
91+
return Bridge.SnippetFilter().apply {
92+
languages = it.languages
93+
selectedLanguages = it.selectedLanguages
94+
}
95+
}
9296
}

0 commit comments

Comments
 (0)