[CS/Refactor] Migrate to MVP style
authorJihoon Lee <jhoon.it.lee@samsung.com>
Tue, 22 Sep 2020 07:23:22 +0000 (16:23 +0900)
committerJijoong Moon <jijoong.moon@samsung.com>
Fri, 25 Sep 2020 04:50:40 +0000 (13:50 +0900)
This patch layouts Customshortcut refactor. It is being migrated
Model-View-Presenter pattern for clarity.

**Changes proposed in this PR:**
- Add `presenter_*` to main presenter function
- Add `util_*` to data for utility function
- Some static function residing in `view.c` has exposed
- Strict segregation between view and data change

See also #577

**Self evaluation:**
1. Build test: [X]Passed [ ]Failed [ ]Skipped
2. Run test: [X]Passed [ ]Failed [ ]Skipped

Signed-off-by: Jihoon Lee <jhoon.it.lee@samsung.com>
Applications/Tizen_native/CustomShortcut/inc/data.h
Applications/Tizen_native/CustomShortcut/inc/main.h
Applications/Tizen_native/CustomShortcut/inc/view.h
Applications/Tizen_native/CustomShortcut/src/data.c
Applications/Tizen_native/CustomShortcut/src/main.c
Applications/Tizen_native/CustomShortcut/src/view.c

index f7377a0..7d6cf79 100644 (file)
@@ -44,6 +44,7 @@ typedef enum DRAW_TARGET_ {
   TRAIN_SMILE,
   TRAIN_FROWN
 } DRAW_TARGET;
+
 typedef struct appdata {
   Evas_Object *win;
   Evas_Object *conform;
@@ -102,7 +103,7 @@ typedef struct train_result {
  * @param[out] length of data len
  * @retval 0 if no error
  */
-int data_parse_route(const char *source, char **route, char **data);
+int util_parse_route(const char *source, char **route, char **data);
 
 /**
  * @brief get full resource path for given file.
@@ -111,28 +112,51 @@ int data_parse_route(const char *source, char **route, char **data);
  * @param[in] shared true if resource is in shared/res
  * @retval APP_ERROR_NONE if no error
  */
-int data_get_resource_path(const char *file, char *full_path, bool shared);
+int util_get_resource_path(const char *file, char *full_path, bool shared);
+
+/**
+ * @brief handle given path_data. If data is invalid, it is essentially noop
+ *
+ * @param ad appdata
+ * @param data path_data to be handled
+ */
+void data_handle_path_data(appdata_s *ad, const char *data);
+
+/**
+ * @brief update draw target from the data. currently the label is depending on
+ * ad->tries only
+ *
+ * @param[in] ad appdata
+ * @return int APP_ERROR_NONE if success
+ */
+int data_update_draw_target(appdata_s *ad);
 
 /**
  * @brief extract data feature from given model.
  * @param[in] ad appdata
- * @param[in] dst state the name of the data set
- * @param[in] append decide whether to append to the exisiting file
  *
  * This function runs a mobilnetv2 last layer detached and saves an output
  * vector. input for this model is png file drawn to the canvas(stored in
  * appdata) output can be pased to nntrainer and used.
  */
-int data_extract_feature(appdata_s *ad, const char *dst, bool append);
+int data_extract_feature(appdata_s *ad);
 
 /**
  * @brief nntrainer training model that is to run from pthread_create
- * @param[in] data appdata.
+ * @param[in] ad appdata.
  * @return not used.
  */
 void *data_run_model(void *ad);
 
 /**
+ * @brief nntrainer update train result from data_run_model
+ *
+ * @param[in] ad appdata
+ * @return not used
+ */
+void *data_update_train_result(void *ad);
+
+/**
  * @brief parse result string
  * @param[in] result result string to be parsed.
  * @param[out] train_result structured data from result string
index c211d03..c1e2c55 100644 (file)
 #ifndef __nntrainer_example_custom_shortcut_H__
 #define __nntrainer_example_custom_shortcut_H__
 
-#include "data.h"
-#include <Elementary.h>
-#include <dlog.h>
 #include <tizen.h>
 
+#include <Elementary.h>
+
+#include "data.h"
+#include "view.h"
+
 #if !defined(PACKAGE)
 #define PACKAGE "org.example.nntrainer-example-custom-shortcut"
 #endif
 
+/**
+ * @brief presenter to handle routing to a page
+ *
+ * @param data appdata
+ * @param obj not used
+ * @param emission not used
+ * @param source string information that has where to go.
+ */
+void presenter_on_routes_request(void *data, Evas_Object *obj EINA_UNUSED,
+                                 const char *emission EINA_UNUSED,
+                                 const char *source);
+
+/**
+ * @brief presenter to handle canvas submission in the inference
+ *
+ * @param data appdata
+ * @param obj not used
+ * @param emission not used
+ * @param source not used
+ */
+void presenter_on_canvas_submit_inference(void *data, Evas_Object *obj,
+                                          const char *emission EINA_UNUSED,
+                                          const char *source EINA_UNUSED);
+
+/**
+ * @brief presenter to handle canvas submission in the training
+ *
+ * @param data appdata
+ * @param obj not used
+ * @param emission not used
+ * @param source not used
+ */
+void presenter_on_canvas_submit_training(void *data, Evas_Object *obj,
+                                         const char *emission EINA_UNUSED,
+                                         const char *source EINA_UNUSED);
+
 #endif /* __nntrainer_example_custom_shortcut_H__ */
index 55ff721..8d3bde1 100644 (file)
 /**
  * @brief initiate window and conformant.
  * @param[in] ad appdata of the app
- * @param[in] w width
- * @param[in] h height
  * @retval #APP_ERROR_*
  */
 int view_init(appdata_s *ad);
 
 /**
- * @brief creates layout from edj
+ * @brief initiate canvas
+ *
+ * @param[in] ad appdata
+ * @return int APP_DATA_NONE when no error
+ */
+int view_init_canvas(appdata_s *ad);
+
+/**
+ * @brief creates layout from edj and push it to the naviframe
  * @param[in/out] ad appdata of the app
- * @param[in] group_name name of the layout to be pushed to main naviframe.
+ * @param[in] path name of the layout to be pushed to main naviframe.
+ */
+int view_routes_to(appdata_s *ad, const char *path);
+
+/**
+ * @brief set canvas clean and update related labels
+ *
+ * @param ad[in] appdata
  */
-int view_routes_to(appdata_s *ad, const char *group_name);
+void view_set_canvas_clean(appdata_s *ad);
 
 /**
  * @brief callback function to update training result
index db438f2..ff69729 100644 (file)
  * @bug No known bugs except for NYI items
  *
  */
-#include "data.h"
 #include <regex.h>
 #include <stdio.h>
 #include <string.h>
 
-int data_parse_route(const char *source, char **route, char **data) {
+#include "data.h"
+
+int util_parse_route(const char *source, char **route, char **data) {
   char *dst = strdup(source);
   const char sep = ':';
   char *i;
@@ -44,7 +45,7 @@ int data_parse_route(const char *source, char **route, char **data) {
   return APP_ERROR_NONE;
 }
 
-int data_get_resource_path(const char *file, char *full_path, bool shared) {
+int util_get_resource_path(const char *file, char *full_path, bool shared) {
   char *root_path;
   if (shared) {
     root_path = app_get_shared_resource_path();
@@ -70,7 +71,7 @@ int data_get_resource_path(const char *file, char *full_path, bool shared) {
   return APP_ERROR_NONE;
 }
 
-int data_get_data_path(const char *file, char *full_path) {
+int util_get_data_path(const char *file, char *full_path) {
   char *root_path;
 
   root_path = app_get_data_path();
@@ -162,14 +163,14 @@ CLEAN:
   pthread_mutex_unlock(&ad->pipe_lock);
 }
 
-static int run_nnpipeline_(appdata_s *ad, const char *src, bool append) {
+static int run_nnpipeline_(appdata_s *ad, const char *src) {
   char pipe_description[5000];
 
   char model_path[PATH_MAX];
 
   int status = ML_ERROR_NONE;
 
-  data_get_resource_path("mobilenetv2.tflite", model_path, false);
+  util_get_resource_path("mobilenetv2.tflite", model_path, false);
 
   status = pthread_mutex_lock(&ad->pipe_lock);
   if (status != 0) {
@@ -237,12 +238,37 @@ CLEAN:
   return status;
 }
 
-int data_extract_feature(appdata_s *ad, const char *dst, bool append) {
+void data_handle_path_data(appdata_s *ad, const char *data) {
+  /// handling path_data to check if it's for inference or path
+  if (!strcmp(data, "inference")) {
+    ad->draw_target = INFER;
+  } else if (!strcmp(data, "train")) {
+    ad->draw_target = TRAIN_UNSET;
+  }
+}
+
+int data_update_draw_target(appdata_s *ad) {
+  switch (ad->tries % NUM_CLASS) {
+  case 0:
+    ad->draw_target = TRAIN_SMILE;
+    return APP_ERROR_NONE;
+  case 1:
+    ad->draw_target = TRAIN_FROWN;
+    return APP_ERROR_NONE;
+  default:
+    LOG_E("Given label is unknown");
+    return APP_ERROR_NOT_SUPPORTED;
+  }
+}
+
+int data_extract_feature(appdata_s *ad) {
   char png_path[PATH_MAX];
+  const char *dst =
+    ad->tries < MAX_TRAIN_TRIES ? TRAIN_SET_PATH : VALIDATION_SET_PATH;
   cairo_status_t cr_stat = CAIRO_STATUS_SUCCESS;
   int status = APP_ERROR_NONE;
 
-  data_get_data_path("temp.png", png_path);
+  util_get_data_path("temp.png", png_path);
   LOG_D("start writing to png_path: %s ", png_path);
   cr_stat = cairo_surface_write_to_png(ad->cr_surface, png_path);
 
@@ -251,10 +277,10 @@ int data_extract_feature(appdata_s *ad, const char *dst, bool append) {
     return APP_ERROR_INVALID_PARAMETER;
   }
 
-  data_get_data_path(dst, ad->pipe_dst);
+  util_get_data_path(dst, ad->pipe_dst);
 
   LOG_I("start inference to dataset: %s ", ad->pipe_dst);
-  status = run_nnpipeline_(ad, png_path, append);
+  status = run_nnpipeline_(ad, png_path);
 
   return status;
 }
@@ -289,8 +315,8 @@ void *data_run_model(void *data) {
   printf("test");
 
   LOG_D("start running model");
-  data_get_resource_path("model.ini", model_conf_path, false);
-  data_get_data_path("label.dat", label_path);
+  util_get_resource_path("model.ini", model_conf_path, false);
+  util_get_data_path("label.dat", label_path);
 
   LOG_D("opening file");
   file = fopen(label_path, "w");
@@ -345,6 +371,37 @@ CLEAN_UP:
   return NULL;
 }
 
+void *data_update_train_result(void *data) {
+  appdata_s *ad = (appdata_s *)data;
+
+  // run model in another thread
+  int read_fd = ad->pipe_fd[0];
+  FILE *fp;
+  char buf[255];
+
+  fp = fdopen(read_fd, "r");
+
+  LOG_D("start waiting to get result");
+
+  ecore_pipe_thaw(ad->data_output_pipe);
+
+  while (fgets(buf, 255, fp) != NULL) {
+    if (ecore_pipe_write(ad->data_output_pipe, buf, 255) == false) {
+      LOG_E("pipe write error");
+      return NULL;
+    };
+    usleep(150);
+  }
+
+  LOG_D("training finished");
+  fclose(fp);
+  close(read_fd);
+  sleep(1);
+  ecore_pipe_freeze(ad->data_output_pipe);
+
+  return NULL;
+}
+
 int data_parse_result_string(const char *src, train_result_s *train_result) {
   // clang-format off
   // #10/10 - Training Loss: 0.398767 >> [ Accuracy: 75% - Validation Loss : 0.467543 ]
index be6d843..9c27f7c 100644 (file)
  * @bug No known bugs except for NYI items
  */
 
-#include "main.h"
-#include "data.h"
-#include "view.h"
 #include <pthread.h>
+
 #include <tizen.h>
 
+#include "data.h"
+#include "main.h"
+#include "view.h"
+
+static int routes_to_(appdata_s *ad, const char *source) {
+  int status = view_routes_to(ad, source);
+  if (status != 0) {
+    LOG_E("routing to a new view failed for %s", source);
+  }
+
+  elm_layout_signal_callback_add(ad->layout, "routes/to", "*",
+                                 &presenter_on_routes_request, ad);
+
+  return status;
+}
+
+static int train_(appdata_s *ad) {
+  int status = ML_ERROR_NONE;
+
+  status = pipe(ad->pipe_fd);
+  if (status < 0) {
+    LOG_E("opening pipe for training failed");
+  }
+
+  ad->best_accuracy = 0.0;
+
+  LOG_D("creating thread to run model");
+  status = pthread_create(&ad->tid_writer, NULL, data_run_model, (void *)ad);
+  if (status < 0) {
+    LOG_E("creating pthread failed %s", strerror(errno));
+    return status;
+  }
+  status = pthread_detach(ad->tid_writer);
+  if (status < 0) {
+    LOG_E("detaching writing thread failed %s", strerror(errno));
+    pthread_cancel(ad->tid_writer);
+  }
+
+  status =
+    pthread_create(&ad->tid_reader, NULL, data_update_train_result, (void *)ad);
+  if (status < 0) {
+    LOG_E("creating pthread failed %s", strerror(errno));
+    return status;
+  }
+  status = pthread_detach(ad->tid_reader);
+  if (status < 0) {
+    LOG_E("detaching reading thread failed %s", strerror(errno));
+    pthread_cancel(ad->tid_writer);
+  }
+
+  return status;
+}
+
+static int init_page_(appdata_s *ad, const char *path) {
+  int status = APP_ERROR_NONE;
+
+  if (!strcmp(path, "draw")) {
+    ad->tries = 0;
+
+    status = view_init_canvas(ad);
+    if (status != APP_ERROR_NONE) {
+      LOG_E("initiating canvas failed");
+      return status;
+    }
+
+    view_set_canvas_clean(ad);
+
+    if (ad->draw_target == INFER) {
+      elm_layout_signal_callback_add(ad->layout, "draw/proceed", "",
+                                     presenter_on_canvas_submit_inference, ad);
+    } else if (ad->draw_target == TRAIN_UNSET) {
+      elm_layout_signal_callback_add(ad->layout, "draw/proceed", "",
+                                     presenter_on_canvas_submit_training, ad);
+    } else {
+      LOG_E("undefined draw target in initiation");
+      return APP_ERROR_INVALID_CONTEXT;
+    }
+    return status;
+  }
+
+  return status;
+}
+
+void presenter_on_routes_request(void *data, Evas_Object *obj EINA_UNUSED,
+                                 const char *emission EINA_UNUSED,
+                                 const char *source) {
+  char *path, *path_data;
+  appdata_s *ad = (appdata_s *)data;
+
+  int status = util_parse_route(source, &path, &path_data);
+  if (status) {
+    LOG_E("something wrong with parsing %s", source);
+    return;
+  }
+
+  LOG_D("%s %s", path, path_data);
+  if (routes_to_(ad, path) != 0)
+    return;
+
+  /// check if path and path_data should be handled in special way,
+  data_handle_path_data(ad, path_data);
+  init_page_(ad, path);
+}
+
+void presenter_on_canvas_submit_inference(void *data, Evas_Object *obj,
+                                          const char *emission,
+                                          const char *source) {
+  /** appdata handling NYI */
+  if (routes_to_((appdata_s *)data, "test_result") != 0)
+    return;
+}
+
+void presenter_on_canvas_submit_training(void *data, Evas_Object *obj,
+                                         const char *emission,
+                                         const char *source) {
+  appdata_s *ad = (appdata_s *)data;
+  int status = APP_ERROR_NONE;
+
+  status = data_update_draw_target(ad);
+  if (status != APP_ERROR_NONE) {
+    LOG_E("setting draw target failed");
+    return;
+  }
+
+  status = data_extract_feature(ad);
+  if (status != APP_ERROR_NONE) {
+    LOG_E("feature extraction failed");
+    return;
+  }
+
+  if (ad->tries == MAX_TRIES - 1) {
+    ad->tries = 0;
+    elm_naviframe_item_pop(ad->naviframe);
+    routes_to_((appdata_s *)data, "train_result");
+    train_(ad);
+  }
+
+  /// prepare next canvas
+  ad->tries++;
+  view_set_canvas_clean(ad);
+}
+
+/********************* app related methods  **************************/
 static bool app_create(void *data) {
   /* Hook to take necessary actions before main event loop starts
      Initialize UI resources and application's data
@@ -33,7 +174,7 @@ static bool app_create(void *data) {
     return false;
   }
 
-  data_get_resource_path(EDJ_PATH, ad->edj_path, false);
+  util_get_resource_path(EDJ_PATH, ad->edj_path, false);
 
   if (chdir(data_path) < 0) {
     LOG_E("change root directory failed");
@@ -44,7 +185,7 @@ static bool app_create(void *data) {
 
   view_init(ad);
 
-  if (view_routes_to(ad, "home"))
+  if (routes_to_(ad, "home"))
     return false;
 
   ad->home = ad->nf_it;
index 9830876..5dff6d2 100644 (file)
@@ -16,9 +16,6 @@ static Evas_Object *create_layout_(Evas_Object *parent, const char *edj_path,
                                    const char *group_name,
                                    Eext_Event_Cb back_cb, void *user_data);
 
-static int create_canvas_(appdata_s *ad, const char *draw_mode);
-static int train(appdata_s *ad);
-
 static void on_win_delete_(void *data, Evas_Object *obj, void *event_info) {
   ui_app_exit();
 }
@@ -47,9 +44,6 @@ static void on_back_pressed_(void *data, Evas_Object *obj, void *event_info) {
   elm_naviframe_item_pop(obj);
 }
 
-static void on_routes_to_(void *data, Evas_Object *obj, const char *emission,
-                          const char *source);
-
 /**
  * @brief initiate window and conformant.
  * @param[in] ad appdata of the app
@@ -118,27 +112,15 @@ int view_init(appdata_s *ad) {
 /**
  * @brief creates layout from edj
  * @param[in/out] ad app data of the add
- * @param[in] group_name name of the layout to be pushed to main naviframe.
+ * @param[in] path name of the layout to be pushed to main naviframe.
  */
-int view_routes_to(appdata_s *ad, const char *group_name) {
-  char *path, *path_data;
-  int status;
-
-  status = data_parse_route(group_name, &path, &path_data);
-  if (status) {
-    LOG_E("something wrong with parsing %s", group_name);
-    return status;
-  }
-
-  LOG_D("%s %s", path, path_data);
+int view_routes_to(appdata_s *ad, const char *path) {
 
   ad->layout = create_layout_(ad->naviframe, ad->edj_path, path, NULL, NULL);
-
   if (ad->layout == NULL) {
     LOG_E("failed to create layout");
-    status = APP_ERROR_INVALID_CONTEXT;
     evas_object_del(ad->win);
-    goto CLEAN_UP;
+    return APP_ERROR_INVALID_CONTEXT;
   }
 
   ad->nf_it = elm_naviframe_item_push(ad->naviframe, NULL, NULL, NULL,
@@ -146,29 +128,10 @@ int view_routes_to(appdata_s *ad, const char *group_name) {
 
   if (ad->nf_it == NULL) {
     LOG_E("naviframe_item_push failed");
-    status = APP_ERROR_INVALID_PARAMETER;
-    goto CLEAN_UP;
-  }
-
-  elm_layout_signal_callback_add(ad->layout, "routes/to", "*", on_routes_to_,
-                                 ad);
-
-  if (!strcmp(path, "draw")) {
-    status = create_canvas_(ad, path_data);
-  }
-
-  if (!strcmp(path, "train_result")) {
-    status = train(ad);
+    return APP_ERROR_INVALID_PARAMETER;
   }
 
-CLEAN_UP:
-  free(path);
-  return status;
-}
-
-static void on_routes_to_(void *data, Evas_Object *obj, const char *emission,
-                          const char *source) {
-  view_routes_to((appdata_s *)data, source);
+  return APP_ERROR_NONE;
 }
 
 /**
@@ -242,36 +205,33 @@ static void on_canvas_exit_(void *data, Evas *e, Evas_Object *obj,
                             void *event_info) {
   LOG_D("deleting canvas");
   appdata_s *ad = (appdata_s *)data;
+  cairo_status_t stat;
 
-  evas_object_del(ad->canvas);
-  cairo_surface_destroy(ad->cr_surface);
-  if (cairo_surface_status(ad->cr_surface) != CAIRO_STATUS_SUCCESS) {
-    LOG_E("delete cr_surface failed");
+  if (ad->cr_surface != NULL) {
+    cairo_surface_destroy(ad->cr_surface);
+    stat = cairo_surface_status(ad->cr_surface);
+    if (stat != CAIRO_STATUS_SUCCESS)
+      LOG_E("delete cr_surface failed reason: %s",
+            cairo_status_to_string(stat));
+    ad->cr_surface = NULL;
   }
-  cairo_destroy(ad->cr);
-  if (cairo_status(ad->cr) != CAIRO_STATUS_SUCCESS) {
-    LOG_E("delete cairo failed");
-  }
-}
 
-static void canvas_erase_all_(appdata_s *ad) {
-  cairo_set_source_rgba(ad->cr, 0.3, 0.3, 0.3, 0.2);
-  cairo_set_operator(ad->cr, CAIRO_OPERATOR_SOURCE);
-  cairo_paint(ad->cr);
-  cairo_surface_flush(ad->cr_surface);
-  evas_object_image_data_update_add(ad->canvas, 0, 0, ad->width, ad->height);
-}
+  if (ad->cr != NULL) {
+    cairo_destroy(ad->cr);
+    stat = cairo_status(ad->cr);
+    if (stat != CAIRO_STATUS_NULL_POINTER)
+      LOG_E("delete cairo failed reason: %s", cairo_status_to_string(stat));
+    ad->cr = NULL;
+  }
 
-static void on_draw_reset_(void *data, Evas_Object *obj, const char *emission,
-                           const char *source) {
-  appdata_s *ad = (appdata_s *)data;
-  LOG_D("draw reset");
-  canvas_erase_all_(ad);
+  evas_object_del(ad->canvas);
 }
 
-static void set_draw_texts_(appdata_s *ad) {
+void view_set_canvas_clean(appdata_s *ad) {
   char buf[256];
   char emoji[5];
+
+  /// setting draw label and text
   switch (ad->draw_target) {
   case INFER:
     strcpy(emoji, "❓");
@@ -291,54 +251,23 @@ static void set_draw_texts_(appdata_s *ad) {
   sprintf(buf, "draw for %s [%d/%d]", emoji, ad->tries + 1, MAX_TRIES);
   elm_object_part_text_set(ad->layout, "draw/title", buf);
   elm_object_part_text_set(ad->layout, "draw/label", emoji);
-}
 
-static void on_draw_proceed_infer_(void *data, Evas_Object *obj,
-                                   const char *emission, const char *source) {
-  view_routes_to((appdata_s *)data, "test_result");
+  /// clear cairo surface
+  cairo_set_source_rgba(ad->cr, 0.3, 0.3, 0.3, 0.2);
+  cairo_set_operator(ad->cr, CAIRO_OPERATOR_SOURCE);
+  cairo_paint(ad->cr);
+  cairo_surface_flush(ad->cr_surface);
+  evas_object_image_data_update_add(ad->canvas, 0, 0, ad->width, ad->height);
 }
 
-static void on_draw_proceed_train_(void *data, Evas_Object *obj,
-                                   const char *emission, const char *source) {
+static void on_draw_reset_(void *data, Evas_Object *obj, const char *emission,
+                           const char *source) {
   appdata_s *ad = (appdata_s *)data;
-  int status = APP_ERROR_NONE;
-
-  switch (ad->tries % NUM_CLASS) {
-  case 0:
-    ad->draw_target = TRAIN_SMILE;
-    break;
-  case 1:
-    ad->draw_target = TRAIN_FROWN;
-    break;
-  default:
-    LOG_E("Given label is unknown");
-    return;
-  }
-
-  LOG_D("labeling proceed");
-  status = data_extract_feature(
-    ad, ad->tries < MAX_TRAIN_TRIES ? TRAIN_SET_PATH : VALIDATION_SET_PATH,
-    true);
-
-  if (status != APP_ERROR_NONE) {
-    LOG_E("feature extraction failed");
-  }
-
-  if (ad->tries == MAX_TRIES - 1) {
-    ad->tries = 0;
-    elm_naviframe_item_pop(ad->naviframe);
-    view_routes_to(ad, "train_result");
-    return;
-  }
-
-  /// prepare next canvas
-  ad->tries++;
-  set_draw_texts_(ad);
-  canvas_erase_all_(ad);
+  LOG_D("draw reset");
+  view_set_canvas_clean(ad);
 }
 
-static int create_canvas_(appdata_s *ad, const char *draw_mode) {
-  LOG_D("init canvas, %s", draw_mode);
+int view_init_canvas(appdata_s *ad) {
   Eina_Bool status;
 
   Evas_Object *frame = elm_layout_add(ad->layout);
@@ -418,18 +347,6 @@ static int create_canvas_(appdata_s *ad, const char *draw_mode) {
   elm_layout_signal_callback_add(ad->layout, "draw/reset", "", on_draw_reset_,
                                  ad);
 
-  if (!strcmp(draw_mode, "inference")) {
-    ad->draw_target = INFER;
-    elm_layout_signal_callback_add(ad->layout, "draw/proceed", "",
-                                   on_draw_proceed_infer_, ad);
-  } else if (!strcmp(draw_mode, "train")) {
-    ad->draw_target = TRAIN_UNSET;
-    elm_layout_signal_callback_add(ad->layout, "draw/proceed", "",
-                                   on_draw_proceed_train_, ad);
-  }
-
-  set_draw_texts_(ad);
-  ad->tries = 0;
   ad->canvas = canvas;
   ad->cr_surface = cairo_surface;
   ad->cr = cr;
@@ -441,74 +358,6 @@ static int create_canvas_(appdata_s *ad, const char *draw_mode) {
   return APP_ERROR_NONE;
 }
 
-static void *process_train_result(void *data) {
-  appdata_s *ad = (appdata_s *)data;
-
-  // run model in another thread
-  int read_fd = ad->pipe_fd[0];
-  FILE *fp;
-  char buf[255];
-
-  fp = fdopen(read_fd, "r");
-
-  LOG_D("start waiting to get result");
-
-  ecore_pipe_thaw(ad->data_output_pipe);
-
-  while (fgets(buf, 255, fp) != NULL) {
-    if (ecore_pipe_write(ad->data_output_pipe, buf, 255) == false) {
-      LOG_E("pipe write error");
-      return NULL;
-    };
-    usleep(150);
-  }
-
-  LOG_D("training finished");
-  fclose(fp);
-  close(read_fd);
-  sleep(1);
-  ecore_pipe_freeze(ad->data_output_pipe);
-
-  return NULL;
-}
-
-static int train(appdata_s *ad) {
-  int status = ML_ERROR_NONE;
-
-  status = pipe(ad->pipe_fd);
-  if (status < 0) {
-    LOG_E("opening pipe for training failed");
-  }
-
-  ad->best_accuracy = 0.0;
-
-  LOG_D("creating thread to run model");
-  status = pthread_create(&ad->tid_writer, NULL, data_run_model, (void *)ad);
-  if (status < 0) {
-    LOG_E("creating pthread failed %s", strerror(errno));
-    return status;
-  }
-  status = pthread_detach(ad->tid_writer);
-  if (status < 0) {
-    LOG_E("detaching writing thread failed %s", strerror(errno));
-    pthread_cancel(ad->tid_writer);
-  }
-
-  status =
-    pthread_create(&ad->tid_reader, NULL, process_train_result, (void *)ad);
-  if (status < 0) {
-    LOG_E("creating pthread failed %s", strerror(errno));
-    return status;
-  }
-  status = pthread_detach(ad->tid_reader);
-  if (status < 0) {
-    LOG_E("detaching reading thread failed %s", strerror(errno));
-    pthread_cancel(ad->tid_writer);
-  }
-
-  return status;
-}
-
 void view_update_result_cb(void *data, void *buffer, unsigned int nbytes) {
   appdata_s *ad = (appdata_s *)data;