diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..39fb081 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.externalNativeBuild diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..7ac24c7 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..5489fee --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + 1.8 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..de72507 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..c795b05 --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..c70e914 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,91 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' +apply plugin: 'realm-android' +apply plugin: 'kotlin-kapt' + +android { + compileSdkVersion 25 + buildToolsVersion "25.0.3" + defaultConfig { + applicationId "ntlab.org.leftoverrecipe" + minSdkVersion 21 + targetSdkVersion 25 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + packagingOptions { + exclude 'META-INF/rxjava.properties' + exclude 'META-INF/DEPENDENCIES.txt' + exclude 'META-INF/LICENSE.txt' + exclude 'META-INF/LICENSE.md' + exclude 'META-INF/NOTICE.txt' + exclude 'META-INF/NOTICE' + exclude 'META-INF/LICENSE' + exclude 'META-INF/DEPENDENCIES' + exclude 'META-INF/notice.txt' + exclude 'META-INF/license.txt' + exclude 'META-INF/dependencies.txt' + exclude 'META-INF/LGPL2.1' + exclude 'META-INF/ASL2.0' + exclude 'META-INF/CONTRIBUTORS.md' + } + dataBinding { + enabled = true + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', { + exclude group: 'com.android.support', module: 'support-annotations' + }) + implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" + implementation 'com.android.support:appcompat-v7:25.4.0' + testImplementation 'junit:junit:4.12' + implementation 'com.android.support.constraint:constraint-layout:1.0.2' + + // Android Desigh + compile 'com.android.support:design:25.4.0' + + // CardView + compile "com.android.support:cardview-v7:25.4.0" + + // Android BootStrap + compile 'com.beardedhen:androidbootstrap:2.3.1' + + // OkHttp + compile 'com.squareup.okhttp3:okhttp:3.7.0' + + // rxJava, rxAndroid + compile 'io.reactivex.rxjava2:rxjava:2.0.0-RC3' + compile 'io.reactivex.rxjava2:rxandroid:2.0.0-RC1' + + // retrofit2 + compile 'com.squareup.retrofit2:converter-gson:2.1.0' + compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0' + compile 'com.squareup.retrofit2:retrofit:2.1.0' + + // jackson + compile 'org.codehaus.jackson:jackson-mapper-asl:1.9.11' + + // Glide + compile 'com.github.bumptech.glide:glide:3.8.0' + + // Kotlin DataBinding + kapt "com.android.databinding:compiler:2.5.0-alpha-preview-02" + + // Kuromoji + compile "com.atilika.kuromoji:kuromoji-ipadic:0.9.0" +} + diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..45bcd7b --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,25 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/matsumoto_k/Library/Android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/app/src/androidTest/java/org/ntlab/leftoverrecipe/ExampleInstrumentedTest.kt b/app/src/androidTest/java/org/ntlab/leftoverrecipe/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..175fe62 --- /dev/null +++ b/app/src/androidTest/java/org/ntlab/leftoverrecipe/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package org.ntlab.leftoverrecipe + +import android.support.test.InstrumentationRegistry +import android.support.test.runner.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getTargetContext() + assertEquals("org.ntlab.leftoverrecipe", appContext.packageName) + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..ec00738 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/App.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/App.kt new file mode 100644 index 0000000..4caf114 --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/App.kt @@ -0,0 +1,14 @@ +package org.ntlab.leftoverrecipe + +import android.app.Application +import com.beardedhen.androidbootstrap.TypefaceProvider + +/** + * Created by matsumoto_k on 2017/05/20 + */ +class App : Application() { + override fun onCreate() { + super.onCreate() + TypefaceProvider.registerDefaultIconSets() + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/activity/DetailRecipeActivity.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/activity/DetailRecipeActivity.kt new file mode 100644 index 0000000..05abda1 --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/activity/DetailRecipeActivity.kt @@ -0,0 +1,29 @@ +package org.ntlab.leftoverrecipe.activity + +import android.databinding.DataBindingUtil +import android.os.Bundle +import android.support.v4.app.FragmentActivity +import com.bumptech.glide.Glide +import kotlinx.android.synthetic.main.activity_detail_recipe.* +import org.ntlab.leftoverrecipe.R +import org.ntlab.leftoverrecipe.api.recipe.RecipeApiResponse +import org.ntlab.leftoverrecipe.databinding.ActivityDetailRecipeBinding +import org.ntlab.leftoverrecipe.viewmodel.DetailRecipeViewModel + +class DetailRecipeActivity : FragmentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_detail_recipe) + + val hoge = intent + val recipeData: RecipeApiResponse.RecipeData = hoge.getSerializableExtra("recipeData") as RecipeApiResponse.RecipeData + + val binding = DataBindingUtil.setContentView(this@DetailRecipeActivity, R.layout.activity_detail_recipe) + val viewModel = DetailRecipeViewModel(this, recipeData) + binding.viewModel = viewModel + + + Glide.with(this).load("").into(hogeImage) + } +} diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/activity/SearchActivity.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/activity/SearchActivity.kt new file mode 100644 index 0000000..d090827 --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/activity/SearchActivity.kt @@ -0,0 +1,47 @@ +package org.ntlab.leftoverrecipe.activity + +import android.app.Activity +import android.content.Intent +import android.databinding.DataBindingUtil +import android.os.Bundle +import android.support.v7.widget.LinearLayoutManager +import kotlinx.android.synthetic.main.activity_search.* +import org.ntlab.leftoverrecipe.R +import org.ntlab.leftoverrecipe.adapter.SearchListAdapter +import org.ntlab.leftoverrecipe.api.recipe.RecipeApiResponse +import org.ntlab.leftoverrecipe.contract.SearchListViewContract +import org.ntlab.leftoverrecipe.databinding.ActivitySearchBinding +import org.ntlab.leftoverrecipe.viewmodel.SearchViewModel + +class SearchActivity : Activity(), SearchListViewContract { + + var adapter: SearchListAdapter? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_search) + + val binding = DataBindingUtil.setContentView(this, R.layout.activity_search) + val viewModel = SearchViewModel(this, this as SearchListViewContract) + binding.viewModel = viewModel + + setupViews() + } + + fun setupViews() { + searchListView.layoutManager = LinearLayoutManager(this) + adapter = SearchListAdapter(this, this as SearchListViewContract) + searchListView.adapter = adapter + } + + override fun showRecipe(response: RecipeApiResponse) { + adapter?.setItemAndRefresh(response.result!!) + } + + + override fun startDetailActivity(recipeData: RecipeApiResponse.RecipeData) { + val intent = Intent(this@SearchActivity, DetailRecipeActivity::class.java) + intent.putExtra("recipeData", recipeData) + startActivity(intent) + } +} diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/adapter/SearchListAdapter.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/adapter/SearchListAdapter.kt new file mode 100644 index 0000000..78c5414 --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/adapter/SearchListAdapter.kt @@ -0,0 +1,63 @@ +package org.ntlab.leftoverrecipe.adapter + +import android.content.Context +import android.databinding.DataBindingUtil +import android.support.v7.widget.RecyclerView +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import kotlinx.android.synthetic.main.search_list_item.view.* +import org.ntlab.leftoverrecipe.R +import org.ntlab.leftoverrecipe.api.recipe.RecipeApiResponse +import org.ntlab.leftoverrecipe.contract.SearchListViewContract +import org.ntlab.leftoverrecipe.databinding.SearchListItemBinding +import org.ntlab.leftoverrecipe.viewmodel.ListItemViewModel + +/** + * Created by matsumoto_k on 2017/05/20 + */ +class SearchListAdapter(var context: Context, var view: SearchListViewContract) : RecyclerView.Adapter() { + + var items: ArrayList? = null + + inner class ViewHolder(itemView: View, viewModel: ListItemViewModel) : RecyclerView.ViewHolder(itemView) { + var viewModel: ListItemViewModel? = null + var imageVieww = itemView?.rootView?.listImageView + + init { + this.viewModel = viewModel + } + + fun loadItem(item: RecipeApiResponse.RecipeData) { + viewModel?.loadItem(item) + } + } + + fun setItemAndRefresh(items: ArrayList) { + println("きたよ") + this.items = items + notifyDataSetChanged() + } + + fun getItemAt(position: Int): RecipeApiResponse.RecipeData? { + return items?.get(position) + } + + override fun onBindViewHolder(holder: ViewHolder?, position: Int) { + val item = getItemAt(position) + holder?.loadItem(item!!) + } + + override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder { + val binding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.search_list_item, parent, false) + binding.viewModel = ListItemViewModel(view) + return ViewHolder(binding.root, binding.viewModel!!) + } + + override fun getItemCount(): Int { + if (items == null) { + return 0 + } + return items?.size!! + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/Api.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/Api.kt new file mode 100644 index 0000000..1082e15 --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/Api.kt @@ -0,0 +1,21 @@ +package org.ntlab.leftoverrecipe.api + +import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory + +/** + * Created by matsumoto_k on 2017/05/20 + */ +abstract class Api { + abstract var endPoint: String + + fun getClient(): Retrofit { + val retrofit = Retrofit.Builder() + .baseUrl(endPoint) + .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + .build() + return retrofit + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/detailrecipe/DetailApi.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/detailrecipe/DetailApi.kt new file mode 100644 index 0000000..bcf2aab --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/detailrecipe/DetailApi.kt @@ -0,0 +1,11 @@ +package org.ntlab.leftoverrecipe.api.recipe + +import org.ntlab.leftoverrecipe.api.Api + +/** + * Created by matsumoto_k on 2017/05/20. + */ +class DetailApi : Api() { + //http://nitta-lab-www2.is.konan-u.ac.jp:8080/ScrapeRecipe/Scrape?recipeUrl=https://recipe.rakuten.co.jp/recipe/1920015991/ + override var endPoint: String = "http://nitta-lab-www2.is.konan-u.ac.jp:8080/" +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/detailrecipe/DetailApiClient.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/detailrecipe/DetailApiClient.kt new file mode 100644 index 0000000..055a2f4 --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/detailrecipe/DetailApiClient.kt @@ -0,0 +1,53 @@ +package org.ntlab.leftoverrecipe.api.recipe + +import io.reactivex.Observer +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers +import org.ntlab.leftoverrecipe.api.Api +import org.ntlab.leftoverrecipe.model.RxBus +import org.ntlab.leftoverrecipe.viewmodel.SearchViewModel + +/** + * Created by matsumoto_k on 2017/05/20. + */ +object DetailApiClient : Api() { + override var endPoint: String = "http://nitta-lab-www2.is.konan-u.ac.jp:8080/" + var connection = false + + fun getRecipeData(recipeUrl: String) { + if (connection) + return + val recipeService = getClient().create(DetailService::class.java).getRecipe(recipeUrl = recipeUrl) + RxBus.send(SearchViewModel.StartRecipeApi) + connection = true + recipeService.subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + object : Observer { + override fun onComplete() { + println("onComplete") + connection = false + } + + override fun onSubscribe(d: Disposable) { + println("onSubscribe") + } + + override fun onNext(response: DetailApiResponse) { + println("onNext") + println("Success") + if (response != null) { + RxBus.send(response) + } + } + + override fun onError(e: Throwable) { + println("onError") + connection = false + println(e.message) + RxBus.send(SearchViewModel.ErrorRecipeApi) + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/detailrecipe/DetailApiResponse.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/detailrecipe/DetailApiResponse.kt new file mode 100644 index 0000000..02ebb63 --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/detailrecipe/DetailApiResponse.kt @@ -0,0 +1,19 @@ +package org.ntlab.leftoverrecipe.api.recipe + +/** + * Created by matsumoto_k on 2017/05/20. + */ +open class DetailApiResponse() { + var anyone: String = "" + var howto: ArrayList = ArrayList() + var material: ArrayList = ArrayList() + + inner class Howto { + var step: String = "" + } + + inner class Material { + var amount: String = "" + var material: String = "" + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/detailrecipe/DetailService.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/detailrecipe/DetailService.kt new file mode 100644 index 0000000..ce119ba --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/detailrecipe/DetailService.kt @@ -0,0 +1,15 @@ +package org.ntlab.leftoverrecipe.api.recipe + +import io.reactivex.Observable +import retrofit2.http.GET +import retrofit2.http.Query + +/** + * Created by matsumoto_k on 2017/05/20. + */ +interface DetailService { + + @GET("ScrapeRecipe/Scrape") + fun getRecipe(@Query("recipeUrl") recipeUrl: String): Observable + +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/recipe/RecipeApi.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/recipe/RecipeApi.kt new file mode 100644 index 0000000..a9c349c --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/recipe/RecipeApi.kt @@ -0,0 +1,10 @@ +package org.ntlab.leftoverrecipe.api.recipe + +import org.ntlab.leftoverrecipe.api.Api + +/** + * Created by matsumoto_k on 2017/05/20. + */ +class RecipeApi : Api() { + override var endPoint: String = "https://app.rakuten.co.jp/" +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/recipe/RecipeApiResponse.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/recipe/RecipeApiResponse.kt new file mode 100644 index 0000000..f875a5f --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/recipe/RecipeApiResponse.kt @@ -0,0 +1,28 @@ +package org.ntlab.leftoverrecipe.api.recipe + +import java.io.Serializable + +/** + * Created by matsumoto_k on 2017/05/20. + */ +open class RecipeApiResponse() { + var result: ArrayList? = null + + class RecipeData : Serializable { + val recipeTitle: String? = null + val foodImageUrl: String? = null + val recipeDescription: String? = null + val recipeMaterial: List? = null + val recipeIndication: String? = null + val recipeCost: String? = null + val mediumImageUrl: String? = null + val smallImageUrl: String? = null + val pickup: Int = 0 + val shop: Int = 0 + val nickname: String? = null + val recipePublishday: String? = null + val rank: String? = null + val recipeId: Int = 0 + val recipeUrl: String? = null + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/recipe/RecipeClient.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/recipe/RecipeClient.kt new file mode 100644 index 0000000..194a198 --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/recipe/RecipeClient.kt @@ -0,0 +1,54 @@ +package org.ntlab.leftoverrecipe.api.recipe + +import io.reactivex.Observer +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers +import org.ntlab.leftoverrecipe.api.Api +import org.ntlab.leftoverrecipe.model.RxBus +import org.ntlab.leftoverrecipe.viewmodel.SearchViewModel + +/** + * Created by matsumoto_k on 2017/05/20. + */ +object RecipeClient : Api() { + override var endPoint: String = "https://app.rakuten.co.jp/" + var connection = false + + fun getRecipeData(categoryId: String) { + if (connection) + return + val recipeService = getClient().create(RecipeService::class.java).getRecipe(categoryId = categoryId) + RxBus.send(SearchViewModel.StartRecipeApi) + connection = true + recipeService.subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + object : Observer { + override fun onComplete() { + println("onComplete") + RxBus.send(SearchViewModel.EndRecipeApi) + connection = false + } + + override fun onSubscribe(d: Disposable) { + println("onSubscribe") + } + + override fun onNext(response: RecipeApiResponse) { + println("onNext") + RxBus.send(SearchViewModel.EndRecipeApi) + if (response != null) { + RxBus.send(response) + } + } + + override fun onError(e: Throwable) { + println("onError") + connection = false + println(e.message) + RxBus.send(SearchViewModel.ErrorRecipeApi) + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/recipe/RecipeService.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/recipe/RecipeService.kt new file mode 100644 index 0000000..32acb10 --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/api/recipe/RecipeService.kt @@ -0,0 +1,15 @@ +package org.ntlab.leftoverrecipe.api.recipe + +import io.reactivex.Observable +import retrofit2.http.GET +import retrofit2.http.Query + +/** + * Created by matsumoto_k on 2017/05/20. + */ +interface RecipeService { + + @GET("services/api/Recipe/CategoryRanking/20121121") + fun getRecipe(@Query("format") format: String = "json", @Query("categoryId") categoryId: String, @Query("applicationId") applicationId: String = "1006988116707470264"): Observable + +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/contract/RegistDialogViewContract.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/contract/RegistDialogViewContract.kt new file mode 100644 index 0000000..d33544c --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/contract/RegistDialogViewContract.kt @@ -0,0 +1,11 @@ +package org.ntlab.leftoverrecipe.contract + +import android.graphics.Bitmap + +/** + * Created by matsumoto_k on 2017/07/06. + */ +interface RegistDialogViewContract { + fun startCamera() + fun getData(): Bitmap +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/contract/SearchListViewContract.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/contract/SearchListViewContract.kt new file mode 100644 index 0000000..643e227 --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/contract/SearchListViewContract.kt @@ -0,0 +1,11 @@ +package org.ntlab.leftoverrecipe.contract + +import org.ntlab.leftoverrecipe.api.recipe.RecipeApiResponse + +/** + * Created by matsumoto_k on 2017/05/20. + */ +interface SearchListViewContract { + fun showRecipe(response: RecipeApiResponse) + fun startDetailActivity(recipeData: RecipeApiResponse.RecipeData) +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/fragment/RegistDialogFragment.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/fragment/RegistDialogFragment.kt new file mode 100644 index 0000000..965f673 --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/fragment/RegistDialogFragment.kt @@ -0,0 +1,67 @@ +package org.ntlab.leftoverrecipe.fragment + +import android.app.Dialog +import android.app.DialogFragment +import android.content.Intent +import android.databinding.DataBindingUtil +import android.graphics.Bitmap +import android.os.Bundle +import android.provider.MediaStore +import android.view.LayoutInflater +import android.view.View +import android.view.WindowManager +import android.widget.ImageView +import org.ntlab.leftoverrecipe.R +import org.ntlab.leftoverrecipe.api.recipe.RecipeApiResponse +import org.ntlab.leftoverrecipe.contract.RegistDialogViewContract +import org.ntlab.leftoverrecipe.databinding.FragmentRegistDialogBinding +import org.ntlab.leftoverrecipe.viewmodel.RegistDialogViewModel + +/** + * Created by matsumoto_k on 2017/05/20. + */ +class RegistDialogFragment(var recipeData: RecipeApiResponse.RecipeData) : DialogFragment(), RegistDialogViewContract { + + var bitmap: Bitmap? = null + + companion object { + val RESULT_CAMERA = 1 + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + + val dialog = Dialog(activity) + val binding = DataBindingUtil.inflate(LayoutInflater.from(dialog.context), R.layout.fragment_regist_dialog, null, false) + dialog.setContentView(binding.root) + dialog.window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT) + val viewModel = RegistDialogViewModel(activity, dialog, recipeData, this as RegistDialogViewContract) + binding.viewModel = viewModel + return dialog + } + + override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { + } + + override fun startCamera() { + val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) + startActivityForResult(intent, RESULT_CAMERA) + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + when (requestCode) { + RESULT_CAMERA -> { + val bitmap = data?.extras?.get("data") as Bitmap + dialog.window.findViewById(R.id.dialogCaptureButton).visibility = View.GONE + val imageView = dialog.window.findViewById(R.id.dialogImageView) as ImageView + imageView.setImageBitmap(bitmap) + imageView.visibility = View.VISIBLE + + this.bitmap = bitmap + } + } + } + + override fun getData(): Bitmap { + return bitmap!! + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/model/RxBus.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/model/RxBus.kt new file mode 100644 index 0000000..faa21e9 --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/model/RxBus.kt @@ -0,0 +1,48 @@ +package org.ntlab.leftoverrecipe.model + +import io.reactivex.Observable +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.disposables.Disposable +import io.reactivex.subjects.PublishSubject + +/** + * Created by matsumoto_k on 2017/05/20. + */ +object RxBus { + + private val subscriptionsMap: HashMap by lazy { + HashMap() + } + + val bus = (PublishSubject.create()).toSerialized() + + fun send(event: Any) { + bus.onNext(event) + } + + inline fun observe(): Observable { + return bus.ofType(eventType::class.java) + } + + fun unregister(subscriber: Any) { + val compositeSubscription = subscriptionsMap[subscriber] + if (compositeSubscription == null) { + } else { + compositeSubscription.clear() + subscriptionsMap.remove(subscriber) + } + } + + internal fun register(subscriber: Any, subscription: Disposable) { + var compositeDisposable = subscriptionsMap[subscriber] + if (compositeDisposable == null) { + compositeDisposable = CompositeDisposable() + } + compositeDisposable.add(subscription) + subscriptionsMap[subscriber] = compositeDisposable + } +} + +fun Disposable.registerInBus(subscriber: Any) { + RxBus.register(subscriber, this) +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/model/db/RealmBase.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/model/db/RealmBase.kt new file mode 100644 index 0000000..bab241b --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/model/db/RealmBase.kt @@ -0,0 +1,20 @@ +package org.ntlab.leftoverrecipe.model.db + +import io.realm.DynamicRealm +import io.realm.RealmConfiguration +import io.realm.RealmMigration + +/** + * Created by matsumoto_k on 2017/07/06. + */ +open class RealmBase { + val config = RealmConfiguration.Builder() + .name("recipe.realm") + .schemaVersion(1) + .migration(object : RealmMigration { + override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { + val schema = realm?.schema + } + }) + .build() +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/model/db/RecipeData.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/model/db/RecipeData.kt new file mode 100644 index 0000000..6388082 --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/model/db/RecipeData.kt @@ -0,0 +1,14 @@ +package org.ntlab.leftoverrecipe.model.db + +import io.realm.RealmObject +import java.util.* + +/** + * Created by matsumoto_k on 2017/07/06. + */ +open class RecipeData( + //open var date: Date = Date(), + open var recipeName: String = "", + open var makeTimeZone: String = "", + open var comment: String = "" +) : RealmObject() \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/model/db/RecipeDataRealm.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/model/db/RecipeDataRealm.kt new file mode 100644 index 0000000..bfb7c4f --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/model/db/RecipeDataRealm.kt @@ -0,0 +1,20 @@ +package org.ntlab.leftoverrecipe.model.db + +import io.realm.Realm + +/** + * Created by matsumoto_k on 2017/07/06. + */ +object RecipeDataRealm : RealmBase() { + var mRealm: Realm? = null + + fun insert(recipeData: RecipeData) { + mRealm = Realm.getInstance(config) + mRealm.use { + realm -> + realm?.executeTransaction { + realm?.copyToRealmOrUpdate(recipeData) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/util/Category.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/util/Category.kt new file mode 100644 index 0000000..be010a0 --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/util/Category.kt @@ -0,0 +1,25 @@ +package org.ntlab.leftoverrecipe.util + +import android.content.Context +import org.codehaus.jackson.map.ObjectMapper +import org.ntlab.leftoverrecipe.R + +/** + * Created by matsumoto_k on 2017/05/20 + */ +class Category { + companion object { + fun getCategoryId(context: Context, material: String): String { + var mapper = ObjectMapper() + val res = context.getResources() + val inputStream = res.openRawResource(R.raw.category) + val root = mapper.readTree(inputStream) + val categoryId = + if (root.get(material) != null) + root.get(material).asText() + else + "30" + return categoryId + } + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/viewmodel/DetailRecipeViewModel.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/viewmodel/DetailRecipeViewModel.kt new file mode 100644 index 0000000..3f55fdc --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/viewmodel/DetailRecipeViewModel.kt @@ -0,0 +1,71 @@ +package org.ntlab.leftoverrecipe.viewmodel + +import android.app.Activity +import android.databinding.BaseObservable +import android.databinding.BindingAdapter +import android.databinding.ObservableField +import android.view.View +import android.widget.ImageView +import com.bumptech.glide.Glide +import org.ntlab.leftoverrecipe.api.recipe.DetailApiClient +import org.ntlab.leftoverrecipe.api.recipe.DetailApiResponse +import org.ntlab.leftoverrecipe.api.recipe.RecipeApiResponse +import org.ntlab.leftoverrecipe.fragment.RegistDialogFragment +import org.ntlab.leftoverrecipe.model.RxBus +import org.ntlab.leftoverrecipe.model.registerInBus + +/** + * Created by matsumoto_k on 2017/05/20 + */ +class DetailRecipeViewModel(var context: Activity, var recipeData: RecipeApiResponse.RecipeData) : BaseObservable() { + val recipeTitle = ObservableField() + val detailTextView = ObservableField() + val imageUrl = ObservableField() + val stepText = ObservableField() + val anyone = ObservableField() + val material = ObservableField() + + companion object { + @JvmStatic @BindingAdapter("imageUrl") + fun imageUrl(imageView: ImageView, url: String) { + println(url) + Glide.with(imageView.context).load(url).into(imageView) + } + } + + init { + println(recipeData.recipeTitle) + recipeTitle.set(recipeData.recipeTitle) + imageUrl.set(recipeData.foodImageUrl) + + load(recipeData.recipeUrl!!) + + RxBus.observe().subscribe { + var stepText = "" + var material = "" + var count = 1 + for (data in it.howto) { + stepText += "${count}.${data.step}\n" + count++ + } + for (data in it.material){ + material+= "${data.amount}\n${data.material}\n\n" + } + println(stepText) + this.stepText.set(stepText) + this.anyone.set(it.anyone) + this.material.set(material) + println("DetailApiResponseRxBus") + }.registerInBus(this) + } + + fun load(recipeUrl: String) { + val recipeClient = DetailApiClient + recipeClient.getRecipeData(recipeUrl) + } + + fun onClickFab(view: View) { + val dialog = RegistDialogFragment(recipeData) + dialog.show(context.fragmentManager, "hoge") + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/viewmodel/ListItemViewModel.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/viewmodel/ListItemViewModel.kt new file mode 100644 index 0000000..ab9a1c1 --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/viewmodel/ListItemViewModel.kt @@ -0,0 +1,47 @@ +package org.ntlab.leftoverrecipe.viewmodel + +import android.databinding.BindingAdapter +import android.databinding.ObservableField +import android.view.View +import android.widget.ImageView +import com.bumptech.glide.Glide +import org.ntlab.leftoverrecipe.api.recipe.DetailApiResponse +import org.ntlab.leftoverrecipe.api.recipe.RecipeApiResponse +import org.ntlab.leftoverrecipe.contract.SearchListViewContract + +/** + * Created by matsumoto_k on 2017/05/20 + */ +class ListItemViewModel(var view: SearchListViewContract) { + var id = ObservableField() + var recipeTitle = ObservableField() + var cost = ObservableField() + var imageUrl = ObservableField() + var description = ObservableField() + var recipeUrl = ObservableField() + var recipeData: RecipeApiResponse.RecipeData? = null + + companion object { + private var url = "" + @JvmStatic @BindingAdapter("bind:imageUrl") + fun imageUrl(imageView: ImageView, url: String) { + println(url) + Glide.with(imageView.context).load(url).into(imageView) + } + } + + fun loadItem(recipeData: RecipeApiResponse.RecipeData) { + id.set(recipeData.recipeId.toString()) + recipeTitle.set(recipeData.recipeTitle) + cost.set(recipeData.recipeCost) + imageUrl.set(recipeData.foodImageUrl) + description.set(recipeData.recipeDescription) + recipeUrl.set(recipeData.recipeUrl) + url = recipeData.recipeUrl!! + this.recipeData = recipeData + } + + fun onItemClick(view: View) { + this.view.startDetailActivity(this.recipeData!!) + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/viewmodel/RegistDialogViewModel.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/viewmodel/RegistDialogViewModel.kt new file mode 100644 index 0000000..37040b3 --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/viewmodel/RegistDialogViewModel.kt @@ -0,0 +1,56 @@ +package org.ntlab.leftoverrecipe.viewmodel + +import android.app.Dialog +import android.content.Context +import android.databinding.BaseObservable +import android.databinding.Bindable +import android.databinding.ObservableField +import android.view.View +import android.widget.Toast +import org.ntlab.leftoverrecipe.api.recipe.RecipeApiResponse +import org.ntlab.leftoverrecipe.contract.RegistDialogViewContract +import org.ntlab.leftoverrecipe.model.db.RecipeData +import org.ntlab.leftoverrecipe.model.db.RecipeDataRealm + +/** + * Created by matsumoto_k on 2017/05/20. + */ +class RegistDialogViewModel(var context: Context, var customDialog: Dialog, var recipeData: RecipeApiResponse.RecipeData, var registDialog: RegistDialogViewContract) : BaseObservable() { + + val recipeTitle = ObservableField() + @Bindable + var recipeName = ObservableField() + @Bindable + var timeZone = ObservableField() + @Bindable + var comment = ObservableField() + + init { + recipeTitle.set(recipeData.recipeTitle) + println(recipeData.recipeTitle) + } + + //RegistDialogのOkButtonListener + fun onClickOk(view: View) { + + //記録する + val recipeData = RecipeData() + recipeData.recipeName = recipeName.get() + recipeData.comment = comment.get() + RecipeDataRealm.insert(recipeData) + + println(comment.get()) + + Toast.makeText(context, "記録しました", Toast.LENGTH_SHORT).show() + customDialog.dismiss() + } + + //RegistDialogのCancelButtonListener + fun onClickCancel(view: View) { + customDialog.dismiss() + } + + fun onClickCapture(view: View) { + registDialog.startCamera() + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/ntlab/leftoverrecipe/viewmodel/SearchViewModel.kt b/app/src/main/kotlin/org/ntlab/leftoverrecipe/viewmodel/SearchViewModel.kt new file mode 100644 index 0000000..a4be55a --- /dev/null +++ b/app/src/main/kotlin/org/ntlab/leftoverrecipe/viewmodel/SearchViewModel.kt @@ -0,0 +1,70 @@ +package org.ntlab.leftoverrecipe.viewmodel + +import android.content.Context +import android.databinding.BaseObservable +import android.databinding.Bindable +import android.databinding.ObservableField +import android.databinding.ObservableInt +import android.view.View +import android.widget.Toast +import org.ntlab.leftoverrecipe.api.recipe.RecipeApiResponse +import org.ntlab.leftoverrecipe.api.recipe.RecipeClient +import org.ntlab.leftoverrecipe.contract.SearchListViewContract +import org.ntlab.leftoverrecipe.model.RxBus +import org.ntlab.leftoverrecipe.model.registerInBus +import org.ntlab.leftoverrecipe.util.Category +import java.sql.DriverManager.println + + +/** + * Created by matsumoto_k on 2017/05/20. + */ +class SearchViewModel(var context: Context, var hoge: SearchListViewContract) : BaseObservable() { + + val progressBarVisibility = ObservableInt(View.GONE) + @Bindable + var materialName: ObservableField = ObservableField() + + companion + + object { + const val StartRecipeApi = "StartRecipeApi" + const val EndRecipeApi = "EndRecipeApi" + const val ErrorRecipeApi = "ErrorRecipeApi" + } + + init { + + RxBus.observe().subscribe { + when (it) { + StartRecipeApi -> progressBarVisibility.set(View.VISIBLE) + EndRecipeApi -> progressBarVisibility.set(View.GONE) + ErrorRecipeApi -> { + progressBarVisibility.set(View.GONE) + //Toast.makeText(context, "通信エラーが発生しました", Toast.LENGTH_SHORT).show() + } + } + }.registerInBus(this) + + RxBus.observe().subscribe { + hoge.showRecipe(it) + for (data in it?.result!!) { + println(data.recipeTitle) + } + }.registerInBus(this) + } + + //検索ボタンクリック + fun onClickSearch(view: View) { + loadRecipe() + } + + fun loadRecipe() { + if (materialName.get() == null) { + Toast.makeText(context, "食材を入力して下さい", Toast.LENGTH_SHORT).show() + return + } + val recipeClient = RecipeClient + recipeClient.getRecipeData(Category.getCategoryId(context, materialName.get())) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/float_regist.png b/app/src/main/res/drawable/float_regist.png new file mode 100644 index 0000000..8f29bf6 --- /dev/null +++ b/app/src/main/res/drawable/float_regist.png Binary files differ diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..1cd2a36 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_detail_recipe.xml b/app/src/main/res/layout/activity_detail_recipe.xml new file mode 100644 index 0000000..d40badc --- /dev/null +++ b/app/src/main/res/layout/activity_detail_recipe.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml new file mode 100644 index 0000000..ebc34a7 --- /dev/null +++ b/app/src/main/res/layout/activity_search.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_regist_dialog.xml b/app/src/main/res/layout/fragment_regist_dialog.xml new file mode 100644 index 0000000..b89056f --- /dev/null +++ b/app/src/main/res/layout/fragment_regist_dialog.xml @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + +