Skip to content

Commit

Permalink
2024-05-07 ToDo App Commit 4
Browse files Browse the repository at this point in the history
  • Loading branch information
htl-leonding committed May 7, 2024
1 parent bf1ee86 commit a7daaa1
Show file tree
Hide file tree
Showing 9 changed files with 177 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import javax.inject.Inject;

import at.htl.todo.model.TodoService;
import dagger.hilt.android.AndroidEntryPoint;

@AndroidEntryPoint
Expand All @@ -23,11 +24,14 @@ public class MainActivity extends ComponentActivity {
@Inject
MainUiBuilder mainUiBuilder;

@Inject
TodoService todoService;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
var url = config.getValue("json.placeholder.baseurl", String.class);
Log.i(TAG,url);
todoService.getAll();
mainUiBuilder.buildContent(this);
}
}
Expand Down
18 changes: 14 additions & 4 deletions labs/TodoAndroid/app/src/main/java/at/htl/todo/MainUiBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.State
import androidx.compose.runtime.rxjava3.subscribeAsState
import at.htl.todo.model.Model
import at.htl.todo.model.ModelStore
import at.htl.todo.ui.theme.TodoAndroidTheme
import javax.inject.Inject
import javax.inject.Singleton
Expand All @@ -18,6 +22,9 @@ class MainUiBuilder {

@Inject constructor(){}

@Inject
lateinit var modelStore: ModelStore

fun buildContent(activity: ComponentActivity) {
activity.setContent {
TodoAndroidTheme {
Expand All @@ -26,7 +33,8 @@ class MainUiBuilder {
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Greeting("Android")
val state = modelStore.pipe.subscribeAsState(initial = Model())
Greeting(state)
}
}
}
Expand All @@ -35,9 +43,11 @@ class MainUiBuilder {
}

@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
fun Greeting(state: State<Model>, modifier: Modifier = Modifier) {


Text(
text = "Hello $name!",
text = "Hello ${state.value.todos.size}!",
modifier = modifier
)
}
Expand All @@ -46,7 +56,7 @@ fun Greeting(name: String, modifier: Modifier = Modifier) {
@Composable
fun GreetingPreview() {
TodoAndroidTheme {
Greeting("Android")
//Greeting("Android")
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package at.htl.todo.model;

import javax.inject.Inject;
import javax.inject.Singleton;

import at.htl.todo.util.store.Store;

/** This is our Storage area for <a href="https://redux.js.org/understanding/thinking-in-redux/three-principles">single source of truth</a> {@link Model}. */
@Singleton
public class ModelStore extends Store<Model> {
@Inject
ModelStore() {
super(Model.class, new Model());
}
public void setTodos(Todo[] todos) {
apply(model -> model.todos = todos);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,30 +1,34 @@
package at.htl.todo.model;

import org.eclipse.microprofile.config.Config;

import java.util.concurrent.CompletableFuture;

import javax.inject.Inject;
import javax.inject.Singleton;

//@Singleton
//public class TodoService {
//
//
// public static final String JSON_PLACEHOLDER_BASE_URL_SETTING = "json.placeholder.baseurl";
// public final String baseUrl;
// public final ToDoClient toDoClient;
// public final ModelStore store;
//
// @Inject
// ToDoService(Config config, RestApiClientBuilder builder, ModelStore store) {
// this.baseUrl = config.getValue(JSON_PLACEHOLDER_BASE_URL_SETTING, String.class);
// toDoClient = builder.build(ToDoClient.class, baseUrl);
// this.store = store;
// }
//
// public void getAll() {
// CompletableFuture
// .supplyAsync(() -> toDoClient.all())
// .thenAccept(store::setTodos);
// }
//
//}
import at.htl.todo.util.resteasy.RestApiClientBuilder;

@Singleton
public class TodoService {

public static final String JSON_PLACEHOLDER_BASE_URL_SETTING = "json.placeholder.baseurl";
public final String baseUrl;
public final TodoClient todoClient;
public final ModelStore modelStore;

@Inject // Hilt verlangt Constructor Injection
TodoService(Config config, RestApiClientBuilder builder, ModelStore modelStore) {
this.baseUrl = config.getValue(JSON_PLACEHOLDER_BASE_URL_SETTING, String.class);
todoClient = builder.build(TodoClient.class, baseUrl);
this.modelStore = modelStore;
}

public void getAll() {
CompletableFuture
.supplyAsync(() -> todoClient.all())
.thenAccept(modelStore::setTodos);
//todoClient.all(); // NetworkOnMainThreadException
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package at.htl.todo.util.immer;

import java.util.function.Consumer;

import javax.inject.Inject;
import javax.inject.Singleton;

import at.htl.todo.util.mapper.Mapper;


/** Immer simplifies handling immutable data structures.
* @see <a>https://immerjs.github.io/immer/</a>
* @see <a>https://redux.js.org/understanding/thinking-in-redux/motivation</a>
*
* @param <T> The type of the baseState
*/
@Singleton
public class Immer<T> {
public final Mapper<T> mapper;

@Inject
public Immer(Class<? extends T> type) {
mapper = new Mapper<T>(type);
}

/**
* @param readonlyState the readonly readonlyState
* @param recipe the callback function that modifies the cloned state
* @return
*/
public T produce(final T readonlyState, Consumer<T> recipe) {
var nextState = mapper.clone(readonlyState);
recipe.accept(nextState);
return nextState;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package at.htl.todo.util.mapper;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import java.io.IOException;

/** A Mapper that maps types to their json representation and back.
* ... plus a convenient deep-clone function
* @param <T> the Class that is mapped
*/
public class Mapper<T> {
private Class<? extends T> clazz;
private ObjectMapper mapper;

public Mapper(Class<? extends T> clazz) {
this.clazz = clazz;
mapper = new ObjectMapper()
.configure(SerializationFeature.INDENT_OUTPUT, true)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); // records
}
public String toResource(T model) {
try {
return mapper.writeValueAsString(model);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public T fromResource(String json) {
T model = null;
try {
model = mapper.readValue(json.getBytes(), clazz);
} catch (IOException e) {
throw new RuntimeException(e);
}
return model;
}
/** deep clone an object by converting it to its json representation and back.
*
* @param thing the thing to clone, unchanged
* @return the deeply cloned thing
*/
public T clone(final T thing) {
return fromResource(toResource(thing));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package at.htl.todo.util.store;

import java.util.concurrent.CompletionException;
import java.util.function.Consumer;

import at.htl.todo.util.immer.Immer;
import io.reactivex.rxjava3.subjects.BehaviorSubject;

public class Store<T> {
public final BehaviorSubject<T> pipe;
public final Immer<T> immer;

protected Store(Class<? extends T> type, T initialState) {
try {
pipe = BehaviorSubject.createDefault(initialState);
immer = new Immer<T>(type);
} catch (Exception e) {
throw new CompletionException(e);
}
}
public void apply(Consumer<T> recipe) {
pipe.onNext(immer.produce(pipe.getValue(), recipe));
}
}
1 change: 1 addition & 0 deletions labs/TodoAndroid/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ plugins {
alias(libs.plugins.androidApplication) apply false
alias(libs.plugins.jetbrainsKotlinAndroid) apply false
id("com.google.dagger.hilt.android") version "2.44" apply false
//id("org.jetbrains.kotlin.jvm") version "1.9.0"
}

0 comments on commit a7daaa1

Please sign in to comment.