diff --git a/BasicSample/app/build.gradle b/BasicSample/app/build.gradle index 79eb18434..a9705bfd7 100644 --- a/BasicSample/app/build.gradle +++ b/BasicSample/app/build.gradle @@ -15,6 +15,8 @@ */ apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-kapt' android { compileSdkVersion 25 @@ -54,7 +56,11 @@ dependencies { compile 'android.arch.lifecycle:extensions:' + rootProject.archLifecycleVersion; compile 'android.arch.persistence.room:runtime:' + rootProject.archRoomVersion; annotationProcessor "android.arch.lifecycle:compiler:" + rootProject.archLifecycleVersion; - annotationProcessor "android.arch.persistence.room:compiler:" + rootProject.archRoomVersion; + kapt "android.arch.persistence.room:compiler:" + rootProject.archRoomVersion + + kapt 'com.android.databinding:compiler:3.0.0-beta2' + compile 'io.reactivex.rxjava2:rxjava:2.1.2' + compile 'io.reactivex.rxjava2:rxandroid:2.0.1' testCompile 'junit:junit:4.12' @@ -72,5 +78,9 @@ dependencies { // Force usage of dependencies in the test app, since it is internally used by the runner module. androidTestCompile 'com.android.support:support-annotations:' + rootProject.supportLibVersion; androidTestCompile 'com.android.support:support-v4:' + rootProject.supportLibVersion; - androidTestCompile 'com.android.support:recyclerview-v7:' + rootProject.supportLibVersion; + androidTestCompile 'com.android.support:recyclerview-v7:' + rootProject.supportLibVersion + compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"; +} +repositories { + mavenCentral() } \ No newline at end of file diff --git a/BasicSample/app/src/androidTest/java/com/example/android/persistence/MainActivityTest.java b/BasicSample/app/src/androidTest/java/com/example/android/persistence/MainActivityTest.java deleted file mode 100644 index b9b899c39..000000000 --- a/BasicSample/app/src/androidTest/java/com/example/android/persistence/MainActivityTest.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2017, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.persistence; - - -import android.arch.lifecycle.Observer; -import android.arch.lifecycle.ViewModelProviders; -import android.support.annotation.Nullable; -import android.support.test.espresso.Espresso; -import android.support.test.espresso.IdlingResource; -import android.support.test.espresso.contrib.RecyclerViewActions; -import android.support.test.rule.ActivityTestRule; -import android.support.v4.app.Fragment; - -import com.example.android.persistence.db.entity.ProductEntity; -import com.example.android.persistence.viewmodel.ProductListViewModel; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; - -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; - -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.action.ViewActions.click; -import static android.support.test.espresso.assertion.ViewAssertions.matches; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription; -import static android.support.test.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.core.IsNot.not; - -public class MainActivityTest { - - @Rule - public ActivityTestRule mActivityRule = new ActivityTestRule<>( - MainActivity.class); - - private SimpleIdlingResource idlingRes = new SimpleIdlingResource(); - - @Before - public void idlingResourceSetup() { - - Espresso.registerIdlingResources(idlingRes); - // There's always - idlingRes.setIdleNow(false); - - ProductListViewModel productListViewModel = getProductListViewModel(); - - // Subscribe to ProductListViewModel's products list observable to figure out when the - // app is idle. - productListViewModel.getProducts().observeForever(new Observer>() { - @Override - public void onChanged(@Nullable List productEntities) { - if (productEntities != null) { - idlingRes.setIdleNow(true); - } - } - }); - } - - @Test - public void clickOnFirstItem_opensComments() { - // When clicking on the first product - onView(withContentDescription(R.string.cd_products_list)) - .perform(RecyclerViewActions.actionOnItemAtPosition(0, click())); - - // Then the second screen with the comments should appear. - onView(withContentDescription(R.string.cd_comments_list)) - .check(matches(isDisplayed())); - - // Then the second screen with the comments should appear. - onView(withContentDescription(R.string.cd_product_name)) - .check(matches(not(withText("")))); - - } - - /** Gets the ViewModel for the current fragment */ - private ProductListViewModel getProductListViewModel() { - MainActivity activity = mActivityRule.getActivity(); - - Fragment productListFragment = activity.getSupportFragmentManager() - .findFragmentByTag(ProductListFragment.TAG); - - return ViewModelProviders.of(productListFragment) - .get(ProductListViewModel.class); - } - - private static class SimpleIdlingResource implements IdlingResource { - - // written from main thread, read from any thread. - private volatile ResourceCallback mResourceCallback; - - private AtomicBoolean mIsIdleNow = new AtomicBoolean(true); - - public void setIdleNow(boolean idleNow) { - mIsIdleNow.set(idleNow); - if (idleNow) { - mResourceCallback.onTransitionToIdle(); - } - } - - @Override - public String getName() { - return "Simple idling resource"; - } - - @Override - public boolean isIdleNow() { - return mIsIdleNow.get(); - } - - @Override - public void registerIdleTransitionCallback(ResourceCallback callback) { - mResourceCallback = callback; - } - } -} \ No newline at end of file diff --git a/BasicSample/app/src/androidTest/java/com/example/android/persistence/MainActivityTest.kt b/BasicSample/app/src/androidTest/java/com/example/android/persistence/MainActivityTest.kt new file mode 100644 index 000000000..b858bd8b8 --- /dev/null +++ b/BasicSample/app/src/androidTest/java/com/example/android/persistence/MainActivityTest.kt @@ -0,0 +1,118 @@ +/* + * Copyright 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.persistence + + +import android.arch.lifecycle.ViewModelProviders +import android.support.test.espresso.Espresso +import android.support.test.espresso.Espresso.onView +import android.support.test.espresso.IdlingResource +import android.support.test.espresso.action.ViewActions.click +import android.support.test.espresso.assertion.ViewAssertions.matches +import android.support.test.espresso.contrib.RecyclerViewActions +import android.support.test.espresso.matcher.ViewMatchers.* +import android.support.test.rule.ActivityTestRule +import android.support.v7.widget.RecyclerView +import android.view.View +import com.example.android.persistence.viewmodel.ProductListViewModel +import org.hamcrest.core.IsNot.not +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import java.util.concurrent.atomic.AtomicBoolean + +class MainActivityTest { + + @Rule + var mActivityRule = ActivityTestRule( + MainActivity::class.java) + + private val idlingRes = SimpleIdlingResource() + + @Before + fun idlingResourceSetup() { + + Espresso.registerIdlingResources(idlingRes) + // There's always + idlingRes.isIdleNow = false + + val productListViewModel = productListViewModel + + // Subscribe to ProductListViewModel's products list observable to figure out when the + // app is idle. + productListViewModel.products.observeForever { productEntities -> + if (productEntities != null) { + idlingRes.isIdleNow = true + } + } + } + + @Test + fun clickOnFirstItem_opensComments() { + // When clicking on the first product + onView(withContentDescription(R.string.cd_products_list)) + .perform(RecyclerViewActions.actionOnItemAtPosition(0, click())) + + // Then the second screen with the comments should appear. + onView(withContentDescription(R.string.cd_comments_list)) + .check(matches(isDisplayed())) + + // Then the second screen with the comments should appear. + onView(withContentDescription(R.string.cd_product_name)) + .check(matches(not(withText("")))) + + } + + /** Gets the ViewModel for the current fragment */ + private val productListViewModel: ProductListViewModel + get() { + val activity = mActivityRule.activity + + val productListFragment = activity.supportFragmentManager + .findFragmentByTag(ProductListFragment.TAG) + + return ViewModelProviders.of(productListFragment) + .get(ProductListViewModel::class.java) + } + + private class SimpleIdlingResource : IdlingResource { + + // written from main thread, read from any thread. + @Volatile private var mResourceCallback: IdlingResource.ResourceCallback? = null + + private val mIsIdleNow = AtomicBoolean(true) + + fun setIdleNow(idleNow: Boolean) { + mIsIdleNow.set(idleNow) + if (idleNow) { + mResourceCallback!!.onTransitionToIdle() + } + } + + override fun getName(): String { + return "Simple idling resource" + } + + override fun isIdleNow(): Boolean { + return mIsIdleNow.get() + } + + override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback) { + mResourceCallback = callback + } + } +} \ No newline at end of file diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/MainActivity.java b/BasicSample/app/src/main/java/com/example/android/persistence/MainActivity.java deleted file mode 100644 index aee825590..000000000 --- a/BasicSample/app/src/main/java/com/example/android/persistence/MainActivity.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2017, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.persistence; - -import android.os.Bundle; -import android.support.annotation.Nullable; - -import android.arch.lifecycle.LifecycleActivity; -import com.example.android.persistence.model.Product; - -public class MainActivity extends LifecycleActivity { - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.main_activity); - - // Add product list fragment if this is first creation - if (savedInstanceState == null) { - ProductListFragment fragment = new ProductListFragment(); - - getSupportFragmentManager().beginTransaction() - .add(R.id.fragment_container, fragment, ProductListFragment.TAG).commit(); - } - } - - /** Shows the product detail fragment */ - public void show(Product product) { - - ProductFragment productFragment = ProductFragment.forProduct(product.getId()); - - getSupportFragmentManager() - .beginTransaction() - .addToBackStack("product") - .replace(R.id.fragment_container, - productFragment, null).commit(); - } -} diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/MainActivity.kt b/BasicSample/app/src/main/java/com/example/android/persistence/MainActivity.kt new file mode 100644 index 000000000..ed91cc377 --- /dev/null +++ b/BasicSample/app/src/main/java/com/example/android/persistence/MainActivity.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.persistence + +import android.os.Bundle + +import android.arch.lifecycle.LifecycleActivity +import com.example.android.persistence.model.Product + +class MainActivity : LifecycleActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.main_activity) + + // Add product list fragment if this is first creation + if(savedInstanceState == null) + supportFragmentManager.beginTransaction() + .add(R.id.fragment_container, ProductListFragment(), ProductListFragment.TAG).commit() + } + + /** Shows the product detail fragment */ + fun show(product: Product) { + supportFragmentManager + .beginTransaction() + .addToBackStack("product") + .replace(R.id.fragment_container, + ProductFragment.forProduct(product.id), null).commit() + } +} diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/ProductFragment.java b/BasicSample/app/src/main/java/com/example/android/persistence/ProductFragment.java deleted file mode 100644 index 4c4014f33..000000000 --- a/BasicSample/app/src/main/java/com/example/android/persistence/ProductFragment.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2017, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.persistence; - -import android.arch.lifecycle.LifecycleFragment; -import android.arch.lifecycle.Observer; -import android.arch.lifecycle.ViewModelProviders; -import android.databinding.DataBindingUtil; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import com.example.android.persistence.databinding.ProductFragmentBinding; -import com.example.android.persistence.db.entity.CommentEntity; -import com.example.android.persistence.db.entity.ProductEntity; -import com.example.android.persistence.model.Comment; -import com.example.android.persistence.ui.CommentAdapter; -import com.example.android.persistence.ui.CommentClickCallback; -import com.example.android.persistence.viewmodel.ProductViewModel; - -import java.util.List; - -public class ProductFragment extends LifecycleFragment { - - private static final String KEY_PRODUCT_ID = "product_id"; - - private ProductFragmentBinding mBinding; - - private CommentAdapter mCommentAdapter; - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - // Inflate this data binding layout - mBinding = DataBindingUtil.inflate(inflater, R.layout.product_fragment, container, false); - - // Create and set the adapter for the RecyclerView. - mCommentAdapter = new CommentAdapter(mCommentClickCallback); - mBinding.commentList.setAdapter(mCommentAdapter); - return mBinding.getRoot(); - } - - private final CommentClickCallback mCommentClickCallback = new CommentClickCallback() { - @Override - public void onClick(Comment comment) { - // no-op - - } - }; - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - ProductViewModel.Factory factory = new ProductViewModel.Factory( - getActivity().getApplication(), getArguments().getInt(KEY_PRODUCT_ID)); - - final ProductViewModel model = ViewModelProviders.of(this, factory) - .get(ProductViewModel.class); - - mBinding.setProductViewModel(model); - - subscribeToModel(model); - } - - private void subscribeToModel(final ProductViewModel model) { - - // Observe product data - model.getObservableProduct().observe(this, new Observer() { - @Override - public void onChanged(@Nullable ProductEntity productEntity) { - model.setProduct(productEntity); - } - }); - - // Observe comments - model.getComments().observe(this, new Observer>() { - @Override - public void onChanged(@Nullable List commentEntities) { - if (commentEntities != null) { - mBinding.setIsLoading(false); - mCommentAdapter.setCommentList(commentEntities); - } else { - mBinding.setIsLoading(true); - } - } - }); - } - - /** Creates product fragment for specific product ID */ - public static ProductFragment forProduct(int productId) { - ProductFragment fragment = new ProductFragment(); - Bundle args = new Bundle(); - args.putInt(KEY_PRODUCT_ID, productId); - fragment.setArguments(args); - return fragment; - } -} diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/ProductFragment.kt b/BasicSample/app/src/main/java/com/example/android/persistence/ProductFragment.kt new file mode 100644 index 000000000..fe7eb07be --- /dev/null +++ b/BasicSample/app/src/main/java/com/example/android/persistence/ProductFragment.kt @@ -0,0 +1,91 @@ +/* + * Copyright 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.persistence + +import android.arch.lifecycle.LifecycleFragment +import android.arch.lifecycle.Observer +import android.arch.lifecycle.ViewModelProviders +import android.databinding.DataBindingUtil +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.example.android.persistence.databinding.ProductFragmentBinding +import com.example.android.persistence.model.Comment +import com.example.android.persistence.ui.CommentAdapter +import com.example.android.persistence.ui.CommentClickCallback +import com.example.android.persistence.viewmodel.ProductViewModel + +class ProductFragment : LifecycleFragment() { + + private lateinit var mBinding: ProductFragmentBinding + + private val mCommentAdapter by lazy { CommentAdapter(mCommentClickCallback) } + + override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + // Inflate this data binding layout + mBinding = DataBindingUtil.inflate(inflater!!, R.layout.product_fragment, container, false) + + // Create and set the adapter for the RecyclerView. + mBinding.commentList.adapter = mCommentAdapter + return mBinding.root + } + + private val mCommentClickCallback = object : CommentClickCallback { + override fun onClick(comment: Comment) {} + // no-op + } + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + val factory = ProductViewModel.Factory( + activity.application, arguments.getInt(KEY_PRODUCT_ID)) + + ViewModelProviders.of(this, factory).get(ProductViewModel::class.java).let { + mBinding.productViewModel = it + + subscribeToModel(it) + } + } + + private fun subscribeToModel(model: ProductViewModel) { + + // Observe product data + model.observableProduct.observe(this, Observer { productEntity -> model.setProduct(productEntity) }) + + // Observe comments + model.comments.observe(this, Observer { commentEntities -> + commentEntities?.let { + mBinding.isLoading = false + mCommentAdapter.setCommentList(it) + } ?: let { mBinding.isLoading = true } + }) + } + + companion object { + + private val KEY_PRODUCT_ID = "product_id" + + /** Creates product fragment for specific product ID */ + fun forProduct(productId: Int): ProductFragment { + val args = Bundle() + args.putInt(KEY_PRODUCT_ID, productId) + return ProductFragment().apply { arguments = args } + } + } +} diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/ProductListFragment.java b/BasicSample/app/src/main/java/com/example/android/persistence/ProductListFragment.java deleted file mode 100644 index 772bc9cba..000000000 --- a/BasicSample/app/src/main/java/com/example/android/persistence/ProductListFragment.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2017, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.persistence; - -import android.arch.lifecycle.Lifecycle; -import android.arch.lifecycle.LifecycleFragment; -import android.arch.lifecycle.Observer; -import android.arch.lifecycle.ViewModelProviders; -import android.databinding.DataBindingUtil; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import com.example.android.persistence.databinding.ListFragmentBinding; -import com.example.android.persistence.db.entity.ProductEntity; -import com.example.android.persistence.model.Product; -import com.example.android.persistence.ui.ProductAdapter; -import com.example.android.persistence.ui.ProductClickCallback; -import com.example.android.persistence.viewmodel.ProductListViewModel; - -import java.util.List; - -public class ProductListFragment extends LifecycleFragment { - - public static final String TAG = "ProductListViewModel"; - - private ProductAdapter mProductAdapter; - - private ListFragmentBinding mBinding; - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - mBinding = DataBindingUtil.inflate(inflater, R.layout.list_fragment, container, false); - - mProductAdapter = new ProductAdapter(mProductClickCallback); - mBinding.productsList.setAdapter(mProductAdapter); - - return mBinding.getRoot(); - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - final ProductListViewModel viewModel = - ViewModelProviders.of(this).get(ProductListViewModel.class); - - subscribeUi(viewModel); - } - - private void subscribeUi(ProductListViewModel viewModel) { - // Update the list when the data changes - viewModel.getProducts().observe(this, new Observer>() { - @Override - public void onChanged(@Nullable List myProducts) { - if (myProducts != null) { - mBinding.setIsLoading(false); - mProductAdapter.setProductList(myProducts); - } else { - mBinding.setIsLoading(true); - } - } - }); - } - - private final ProductClickCallback mProductClickCallback = new ProductClickCallback() { - @Override - public void onClick(Product product) { - - if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) { - ((MainActivity) getActivity()).show(product); - } - } - }; -} diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/ProductListFragment.kt b/BasicSample/app/src/main/java/com/example/android/persistence/ProductListFragment.kt new file mode 100644 index 000000000..53f05bb55 --- /dev/null +++ b/BasicSample/app/src/main/java/com/example/android/persistence/ProductListFragment.kt @@ -0,0 +1,78 @@ +/* + * Copyright 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.persistence + +import android.arch.lifecycle.Lifecycle +import android.arch.lifecycle.LifecycleFragment +import android.arch.lifecycle.Observer +import android.arch.lifecycle.ViewModelProviders +import android.databinding.DataBindingUtil +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.example.android.persistence.databinding.ListFragmentBinding +import com.example.android.persistence.model.Product +import com.example.android.persistence.ui.ProductAdapter +import com.example.android.persistence.ui.ProductClickCallback +import com.example.android.persistence.viewmodel.ProductListViewModel + +class ProductListFragment : LifecycleFragment() { + + private val mProductAdapter by lazy { ProductAdapter(mProductClickCallback) } + + private lateinit var mBinding: ListFragmentBinding + + override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + mBinding = DataBindingUtil.inflate(inflater!!, R.layout.list_fragment, container, false) + + mBinding.productsList.adapter = mProductAdapter + + return mBinding.root + } + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + val viewModel = ViewModelProviders.of(this).get(ProductListViewModel::class.java) + + subscribeUi(viewModel) + } + + private fun subscribeUi(viewModel: ProductListViewModel) { + // Update the list when the data changes + viewModel.products.observe(this, Observer { myProducts -> + myProducts?.let { + mBinding.isLoading = false + mProductAdapter.setProductList(it) + } ?: let { mBinding.isLoading = true } + }) + } + + private val mProductClickCallback = object : ProductClickCallback { + override fun onClick(product: Product) { + if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) { + (activity as MainActivity).show(product) + } + } + } + + companion object { + + const val TAG = "ProductListViewModel" + } +} diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/db/AppDatabase.java b/BasicSample/app/src/main/java/com/example/android/persistence/db/AppDatabase.java deleted file mode 100644 index ce0afe4b2..000000000 --- a/BasicSample/app/src/main/java/com/example/android/persistence/db/AppDatabase.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2017, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.persistence.db; - -import android.arch.persistence.room.Database; -import android.arch.persistence.room.RoomDatabase; -import android.arch.persistence.room.TypeConverters; - -import com.example.android.persistence.db.dao.CommentDao; -import com.example.android.persistence.db.dao.ProductDao; -import com.example.android.persistence.db.entity.CommentEntity; -import com.example.android.persistence.db.entity.ProductEntity; -import com.example.android.persistence.db.converter.DateConverter; - -@Database(entities = {ProductEntity.class, CommentEntity.class}, version = 1) -@TypeConverters(DateConverter.class) -public abstract class AppDatabase extends RoomDatabase { - - static final String DATABASE_NAME = "basic-sample-db"; - - public abstract ProductDao productDao(); - - public abstract CommentDao commentDao(); -} diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/db/AppDatabase.kt b/BasicSample/app/src/main/java/com/example/android/persistence/db/AppDatabase.kt new file mode 100644 index 000000000..133ff71f6 --- /dev/null +++ b/BasicSample/app/src/main/java/com/example/android/persistence/db/AppDatabase.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.persistence.db + +import android.arch.persistence.room.Database +import android.arch.persistence.room.RoomDatabase +import android.arch.persistence.room.TypeConverters + +import com.example.android.persistence.db.dao.CommentDao +import com.example.android.persistence.db.dao.ProductDao +import com.example.android.persistence.db.entity.CommentEntity +import com.example.android.persistence.db.entity.ProductEntity +import com.example.android.persistence.db.converter.DateConverter + +@Database(entities = arrayOf(ProductEntity::class, CommentEntity::class), version = 1) +@TypeConverters(DateConverter::class) +abstract class AppDatabase : RoomDatabase() { + + abstract fun productDao(): ProductDao + + abstract fun commentDao(): CommentDao + + companion object { + val DATABASE_NAME = "basic-sample-db" + } +} diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/db/DatabaseCreator.java b/BasicSample/app/src/main/java/com/example/android/persistence/db/DatabaseCreator.java deleted file mode 100644 index 5ecb8847a..000000000 --- a/BasicSample/app/src/main/java/com/example/android/persistence/db/DatabaseCreator.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2017, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.persistence.db; - -import android.arch.lifecycle.LiveData; -import android.arch.lifecycle.MutableLiveData; -import android.arch.persistence.room.Room; -import android.content.Context; -import android.os.AsyncTask; -import android.support.annotation.Nullable; -import android.util.Log; - -import java.util.concurrent.atomic.AtomicBoolean; - -import static com.example.android.persistence.db.AppDatabase.DATABASE_NAME; - -/** - * Creates the {@link AppDatabase} asynchronously, exposing a LiveData object to notify of creation. - */ -public class DatabaseCreator { - - private static DatabaseCreator sInstance; - - private final MutableLiveData mIsDatabaseCreated = new MutableLiveData<>(); - - private AppDatabase mDb; - - private final AtomicBoolean mInitializing = new AtomicBoolean(true); - - // For Singleton instantiation - private static final Object LOCK = new Object(); - - public synchronized static DatabaseCreator getInstance(Context context) { - if (sInstance == null) { - synchronized (LOCK) { - if (sInstance == null) { - sInstance = new DatabaseCreator(); - } - } - } - return sInstance; - } - - /** Used to observe when the database initialization is done */ - public LiveData isDatabaseCreated() { - return mIsDatabaseCreated; - } - - @Nullable - public AppDatabase getDatabase() { - return mDb; - } - - /** - * Creates or returns a previously-created database. - *

- * Although this uses an AsyncTask which currently uses a serial executor, it's thread-safe. - */ - public void createDb(Context context) { - - Log.d("DatabaseCreator", "Creating DB from " + Thread.currentThread().getName()); - - if (!mInitializing.compareAndSet(true, false)) { - return; // Already initializing - } - - mIsDatabaseCreated.setValue(false);// Trigger an update to show a loading screen. - new AsyncTask() { - - @Override - protected Void doInBackground(Context... params) { - Log.d("DatabaseCreator", - "Starting bg job " + Thread.currentThread().getName()); - - Context context = params[0].getApplicationContext(); - - // Reset the database to have new data on every run. - context.deleteDatabase(DATABASE_NAME); - - // Build the database! - AppDatabase db = Room.databaseBuilder(context.getApplicationContext(), - AppDatabase.class, DATABASE_NAME).build(); - - // Add a delay to simulate a long-running operation - addDelay(); - - // Add some data to the database - DatabaseInitUtil.initializeDb(db); - Log.d("DatabaseCreator", - "DB was populated in thread " + Thread.currentThread().getName()); - - mDb = db; - return null; - } - - @Override - protected void onPostExecute(Void ignored) { - // Now on the main thread, notify observers that the db is created and ready. - mIsDatabaseCreated.setValue(true); - } - }.execute(context.getApplicationContext()); - } - - private void addDelay() { - try { - Thread.sleep(4000); - } catch (InterruptedException ignored) {} - } -} diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/db/DatabaseCreator.kt b/BasicSample/app/src/main/java/com/example/android/persistence/db/DatabaseCreator.kt new file mode 100644 index 000000000..c015f694a --- /dev/null +++ b/BasicSample/app/src/main/java/com/example/android/persistence/db/DatabaseCreator.kt @@ -0,0 +1,103 @@ +/* + * Copyright 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.persistence.db + +import android.arch.lifecycle.LiveData +import android.arch.lifecycle.MutableLiveData +import android.arch.persistence.room.Room +import android.content.Context +import android.os.AsyncTask +import android.util.Log +import com.example.android.persistence.db.AppDatabase.Companion.DATABASE_NAME + +import java.util.concurrent.atomic.AtomicBoolean + +import io.reactivex.Flowable +import io.reactivex.Scheduler +import io.reactivex.schedulers.Schedulers + +import io.reactivex.android.schedulers.AndroidSchedulers + +/** + * Creates the [AppDatabase] asynchronously, exposing a LiveData object to notify of creation. + */ +class DatabaseCreator { + + private val mIsDatabaseCreated = MutableLiveData() + + var database: AppDatabase? = null + private set + + private val mInitializing = AtomicBoolean(true) + + /** Used to observe when the database initialization is done */ + val isDatabaseCreated: LiveData + get() = mIsDatabaseCreated + + /** + * Creates or returns a previously-created database. + * + * + * Although this uses an AsyncTask which currently uses a serial executor, it's thread-safe. + */ + fun createDb(context: Context) { + Log.d("DatabaseCreator", "Creating DB from " + Thread.currentThread().name) + + if (!mInitializing.compareAndSet(true, false)) { + return // Already initializing + } + + mIsDatabaseCreated.value = false// Trigger an update to show a loading screen. + + Flowable.just(context.applicationContext) + .subscribeOn(Schedulers.io()) + .doOnNext { c -> c.deleteDatabase(DATABASE_NAME) } + .map { Room.databaseBuilder(it.applicationContext, AppDatabase::class.java, DATABASE_NAME).build() } + .doOnNext { addDelay() } + .doOnNext { DatabaseInitUtil.initializeDb(it) } + .doOnNext { database = it } + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { mIsDatabaseCreated.value = true } + } + + private fun addDelay() { + try { + Thread.sleep(4000) + } catch (ignored: InterruptedException) { + } + + } + companion object { + + private var sInstance: DatabaseCreator? = null + + // For Singleton instantiation + private val LOCK = Any() + + @Synchronized + fun getInstance(context: Context): DatabaseCreator { + if (sInstance == null) { + synchronized(LOCK) { + if (sInstance == null) { + sInstance = DatabaseCreator() + } + } + } + return sInstance!! + } + } +} diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/db/DatabaseInitUtil.java b/BasicSample/app/src/main/java/com/example/android/persistence/db/DatabaseInitUtil.java deleted file mode 100644 index c68fe8fad..000000000 --- a/BasicSample/app/src/main/java/com/example/android/persistence/db/DatabaseInitUtil.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2017, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.persistence.db; - -import com.example.android.persistence.db.entity.CommentEntity; -import com.example.android.persistence.db.entity.ProductEntity; -import com.example.android.persistence.model.Product; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Random; -import java.util.concurrent.TimeUnit; - -/** Generates dummy data and inserts them into the database */ -class DatabaseInitUtil { - - private static final String[] FIRST = new String[]{ - "Special edition", "New", "Cheap", "Quality", "Used"}; - private static final String[] SECOND = new String[]{ - "Three-headed Monkey", "Rubber Chicken", "Pint of Grog", "Monocle"}; - private static final String[] DESCRIPTION = new String[]{ - "is finally here", "is recommended by Stan S. Stanman", - "is the best sold product on Mêlée Island", "is \uD83D\uDCAF", "is ❤️", "is fine"}; - private static final String[] COMMENTS = new String[]{ - "Comment 1", "Comment 2", "Comment 3", "Comment 4", "Comment 5", "Comment 6", - }; - - static void initializeDb(AppDatabase db) { - List products = new ArrayList<>(FIRST.length * SECOND.length); - List comments = new ArrayList<>(); - - generateData(products, comments); - - insertData(db, products, comments); - } - - private static void generateData(List products, List comments) { - Random rnd = new Random(); - for (int i = 0; i < FIRST.length; i++) { - for (int j = 0; j < SECOND.length; j++) { - ProductEntity product = new ProductEntity(); - product.setName(FIRST[i] + " " + SECOND[j]); - product.setDescription(product.getName() + " " + DESCRIPTION[j]); - product.setPrice(rnd.nextInt(240)); - product.setId(FIRST.length * i + j + 1); - products.add(product); - } - } - - for (Product product : products) { - int commentsNumber = rnd.nextInt(5) + 1; - for (int i = 0; i < commentsNumber; i++) { - CommentEntity comment = new CommentEntity(); - comment.setProductId(product.getId()); - comment.setText(COMMENTS[i] + " for " + product.getName()); - comment.setPostedAt(new Date(System.currentTimeMillis() - - TimeUnit.DAYS.toMillis(commentsNumber - i) + TimeUnit.HOURS.toMillis(i))); - comments.add(comment); - } - } - } - - private static void insertData(AppDatabase db, List products, List comments) { - db.beginTransaction(); - try { - db.productDao().insertAll(products); - db.commentDao().insertAll(comments); - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); - } - } -} diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/db/DatabaseInitUtil.kt b/BasicSample/app/src/main/java/com/example/android/persistence/db/DatabaseInitUtil.kt new file mode 100644 index 000000000..651f221c6 --- /dev/null +++ b/BasicSample/app/src/main/java/com/example/android/persistence/db/DatabaseInitUtil.kt @@ -0,0 +1,78 @@ +/* + * Copyright 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.persistence.db + +import com.example.android.persistence.db.entity.CommentEntity +import com.example.android.persistence.db.entity.ProductEntity +import com.example.android.persistence.model.Product + +import java.util.ArrayList +import java.util.Date +import java.util.Random +import java.util.concurrent.TimeUnit + +/** Generates dummy data and inserts them into the database */ +internal object DatabaseInitUtil { + + private val FIRST = arrayOf("Special edition", "New", "Cheap", "Quality", "Used") + private val SECOND = arrayOf("Three-headed Monkey", "Rubber Chicken", "Pint of Grog", "Monocle") + private val DESCRIPTION = arrayOf("is finally here", "is recommended by Stan S. Stanman", "is the best sold product on Mêlée Island", "is \uD83D\uDCAF", "is ❤️", "is fine") + private val COMMENTS = arrayOf("Comment 1", "Comment 2", "Comment 3", "Comment 4", "Comment 5", "Comment 6") + + fun initializeDb(db: AppDatabase) { + val products = ArrayList(FIRST.size * SECOND.size) + val comments = ArrayList() + + generateData(products, comments) + + insertData(db, products, comments) + } + + private fun generateData(products: MutableList, comments: MutableList) { + val rnd = Random() + for (i in FIRST.indices) { + for (j in SECOND.indices) { + + val id = FIRST.size * i + j + 1 + val name = FIRST[i] + " " + SECOND[j] + val description = name + FIRST.size * i + j + 1 + val price = FIRST.size * i + j + 1 + val product = ProductEntity(id, name, description, price) + products.add(product) + } + } + + for ((id, name) in products) { + val commentsNumber = rnd.nextInt(5) + 1 + (0 until commentsNumber).mapTo(comments) { + CommentEntity(0, id, COMMENTS[it] + " for " + name, + Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis((commentsNumber - it).toLong()) + TimeUnit.HOURS.toMillis(it.toLong()))) + } + } + } + + private fun insertData(db: AppDatabase, products: List, comments: List) { + db.beginTransaction() + try { + db.productDao().insertAll(products) + db.commentDao().insertAll(comments) + db.setTransactionSuccessful() + } finally { + db.endTransaction() + } + } +} diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/db/converter/DateConverter.kt b/BasicSample/app/src/main/java/com/example/android/persistence/db/converter/DateConverter.kt new file mode 100644 index 000000000..4d14e02af --- /dev/null +++ b/BasicSample/app/src/main/java/com/example/android/persistence/db/converter/DateConverter.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.persistence.db.converter + +import android.arch.persistence.room.TypeConverter + +import java.util.Date + +object DateConverter { + + @JvmStatic + @TypeConverter + fun toDate(timestamp: Long?): Date? = timestamp?.let { Date(it) } + + @JvmStatic + @TypeConverter + fun toTimestamp(date: Date?): Long? = date?.time +} diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/db/dao/CommentDao.java b/BasicSample/app/src/main/java/com/example/android/persistence/db/dao/CommentDao.kt similarity index 59% rename from BasicSample/app/src/main/java/com/example/android/persistence/db/dao/CommentDao.java rename to BasicSample/app/src/main/java/com/example/android/persistence/db/dao/CommentDao.kt index b351526cf..42c3f570b 100644 --- a/BasicSample/app/src/main/java/com/example/android/persistence/db/dao/CommentDao.java +++ b/BasicSample/app/src/main/java/com/example/android/persistence/db/dao/CommentDao.kt @@ -14,27 +14,25 @@ * limitations under the License. */ -package com.example.android.persistence.db.dao; +package com.example.android.persistence.db.dao -import android.arch.lifecycle.LiveData; -import android.arch.persistence.room.Dao; -import android.arch.persistence.room.Insert; -import android.arch.persistence.room.OnConflictStrategy; -import android.arch.persistence.room.Query; +import android.arch.lifecycle.LiveData +import android.arch.persistence.room.Dao +import android.arch.persistence.room.Insert +import android.arch.persistence.room.OnConflictStrategy +import android.arch.persistence.room.Query -import com.example.android.persistence.db.entity.CommentEntity; - -import java.util.List; +import com.example.android.persistence.db.entity.CommentEntity @Dao -public interface CommentDao { +interface CommentDao { @Query("SELECT * FROM comments where productId = :productId") - LiveData> loadComments(int productId); + fun loadComments(productId: Int): LiveData> @Query("SELECT * FROM comments where productId = :productId") - List loadCommentsSync(int productId); + fun loadCommentsSync(productId: Int): List @Insert(onConflict = OnConflictStrategy.REPLACE) - void insertAll(List products); + fun insertAll(products: List) } diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/db/dao/ProductDao.java b/BasicSample/app/src/main/java/com/example/android/persistence/db/dao/ProductDao.kt similarity index 58% rename from BasicSample/app/src/main/java/com/example/android/persistence/db/dao/ProductDao.java rename to BasicSample/app/src/main/java/com/example/android/persistence/db/dao/ProductDao.kt index 39407d06d..d8b5271cd 100644 --- a/BasicSample/app/src/main/java/com/example/android/persistence/db/dao/ProductDao.java +++ b/BasicSample/app/src/main/java/com/example/android/persistence/db/dao/ProductDao.kt @@ -14,29 +14,27 @@ * limitations under the License. */ -package com.example.android.persistence.db.dao; +package com.example.android.persistence.db.dao -import android.arch.lifecycle.LiveData; -import android.arch.persistence.room.Dao; -import android.arch.persistence.room.Insert; -import android.arch.persistence.room.OnConflictStrategy; -import android.arch.persistence.room.Query; +import android.arch.lifecycle.LiveData +import android.arch.persistence.room.Dao +import android.arch.persistence.room.Insert +import android.arch.persistence.room.OnConflictStrategy +import android.arch.persistence.room.Query -import com.example.android.persistence.db.entity.ProductEntity; - -import java.util.List; +import com.example.android.persistence.db.entity.ProductEntity @Dao -public interface ProductDao { +interface ProductDao { @Query("SELECT * FROM products") - LiveData> loadAllProducts(); + fun loadAllProducts(): LiveData> @Insert(onConflict = OnConflictStrategy.REPLACE) - void insertAll(List products); + fun insertAll(products: List) @Query("select * from products where id = :productId") - LiveData loadProduct(int productId); + fun loadProduct(productId: Int): LiveData @Query("select * from products where id = :productId") - ProductEntity loadProductSync(int productId); + fun loadProductSync(productId: Int): ProductEntity } diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/db/entity/CommentEntity.java b/BasicSample/app/src/main/java/com/example/android/persistence/db/entity/CommentEntity.java deleted file mode 100644 index e3d5702c1..000000000 --- a/BasicSample/app/src/main/java/com/example/android/persistence/db/entity/CommentEntity.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2017, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.persistence.db.entity; - -import android.arch.persistence.room.Entity; -import android.arch.persistence.room.ForeignKey; -import android.arch.persistence.room.Index; -import android.arch.persistence.room.PrimaryKey; -import com.example.android.persistence.model.Comment; - -import java.util.Date; - -@Entity(tableName = "comments", foreignKeys = { - @ForeignKey(entity = ProductEntity.class, - parentColumns = "id", - childColumns = "productId", - onDelete = ForeignKey.CASCADE)}, indices = { - @Index(value = "productId") -}) -public class CommentEntity implements Comment { - @PrimaryKey(autoGenerate = true) - private int id; - private int productId; - private String text; - private Date postedAt; - - @Override - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - @Override - public int getProductId() { - return productId; - } - - public void setProductId(int productId) { - this.productId = productId; - } - - @Override - public String getText() { - return text; - } - - public void setText(String text) { - this.text = text; - } - - @Override - public Date getPostedAt() { - return postedAt; - } - - public void setPostedAt(Date postedAt) { - this.postedAt = postedAt; - } - - public CommentEntity() { - } - - public CommentEntity(Comment comment) { - id = comment.getId(); - productId = comment.getProductId(); - text = comment.getText(); - postedAt = comment.getPostedAt(); - } -} diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/db/entity/CommentEntity.kt b/BasicSample/app/src/main/java/com/example/android/persistence/db/entity/CommentEntity.kt new file mode 100644 index 000000000..147d06290 --- /dev/null +++ b/BasicSample/app/src/main/java/com/example/android/persistence/db/entity/CommentEntity.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.persistence.db.entity + +import android.arch.persistence.room.Entity +import android.arch.persistence.room.ForeignKey +import android.arch.persistence.room.Index +import android.arch.persistence.room.PrimaryKey +import com.example.android.persistence.model.Comment + +import java.util.Date + +@Entity(tableName = "comments", + foreignKeys = arrayOf(ForeignKey( + entity = ProductEntity::class, + parentColumns = arrayOf("id"), + childColumns = arrayOf("productId"), + onDelete = ForeignKey.CASCADE)), + indices = arrayOf(Index(value = "productId"))) +data class CommentEntity(@PrimaryKey(autoGenerate = true) + override var id: Int, + override var productId: Int, + override var text: String?, + override var postedAt: Date?) : Comment diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/db/entity/ProductEntity.java b/BasicSample/app/src/main/java/com/example/android/persistence/db/entity/ProductEntity.java deleted file mode 100644 index af1b79a9b..000000000 --- a/BasicSample/app/src/main/java/com/example/android/persistence/db/entity/ProductEntity.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2017, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.persistence.db.entity; - -import android.arch.persistence.room.Entity; -import android.arch.persistence.room.PrimaryKey; - -import com.example.android.persistence.model.Product; - -@Entity(tableName = "products") -public class ProductEntity implements Product { - @PrimaryKey - private int id; - private String name; - private String description; - private int price; - - @Override - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - @Override - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - @Override - public int getPrice() { - return price; - } - - public void setPrice(int price) { - this.price = price; - } - - public ProductEntity() { - } - - public ProductEntity(Product product) { - this.id = product.getId(); - this.name = product.getName(); - this.description = product.getDescription(); - this.price = product.getPrice(); - } -} diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/db/converter/DateConverter.java b/BasicSample/app/src/main/java/com/example/android/persistence/db/entity/ProductEntity.kt similarity index 56% rename from BasicSample/app/src/main/java/com/example/android/persistence/db/converter/DateConverter.java rename to BasicSample/app/src/main/java/com/example/android/persistence/db/entity/ProductEntity.kt index da5fe2286..fc8a624ae 100644 --- a/BasicSample/app/src/main/java/com/example/android/persistence/db/converter/DateConverter.java +++ b/BasicSample/app/src/main/java/com/example/android/persistence/db/entity/ProductEntity.kt @@ -14,20 +14,16 @@ * limitations under the License. */ -package com.example.android.persistence.db.converter; +package com.example.android.persistence.db.entity -import android.arch.persistence.room.TypeConverter; +import android.arch.persistence.room.Entity +import android.arch.persistence.room.PrimaryKey -import java.util.Date; +import com.example.android.persistence.model.Product -public class DateConverter { - @TypeConverter - public static Date toDate(Long timestamp) { - return timestamp == null ? null : new Date(timestamp); - } - - @TypeConverter - public static Long toTimestamp(Date date) { - return date == null ? null : date.getTime(); - } -} +@Entity(tableName = "products") +data class ProductEntity(@PrimaryKey + override var id: Int, + override var name: String?, + override var description: String?, + override var price: Int) : Product diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/ui/CommentClickCallback.java b/BasicSample/app/src/main/java/com/example/android/persistence/model/Comment.kt similarity index 78% rename from BasicSample/app/src/main/java/com/example/android/persistence/ui/CommentClickCallback.java rename to BasicSample/app/src/main/java/com/example/android/persistence/model/Comment.kt index ced806597..ca4a2e8bd 100644 --- a/BasicSample/app/src/main/java/com/example/android/persistence/ui/CommentClickCallback.java +++ b/BasicSample/app/src/main/java/com/example/android/persistence/model/Comment.kt @@ -14,10 +14,13 @@ * limitations under the License. */ -package com.example.android.persistence.ui; +package com.example.android.persistence.model -import com.example.android.persistence.model.Comment; +import java.util.Date -public interface CommentClickCallback { - void onClick(Comment comment); +interface Comment { + val id: Int + val productId: Int + val text: String? + val postedAt: Date? } diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/model/Product.java b/BasicSample/app/src/main/java/com/example/android/persistence/model/Product.kt similarity index 79% rename from BasicSample/app/src/main/java/com/example/android/persistence/model/Product.java rename to BasicSample/app/src/main/java/com/example/android/persistence/model/Product.kt index 72e427696..d34cc239e 100644 --- a/BasicSample/app/src/main/java/com/example/android/persistence/model/Product.java +++ b/BasicSample/app/src/main/java/com/example/android/persistence/model/Product.kt @@ -14,11 +14,11 @@ * limitations under the License. */ -package com.example.android.persistence.model; +package com.example.android.persistence.model -public interface Product { - int getId(); - String getName(); - String getDescription(); - int getPrice(); +interface Product { + val id: Int + val name: String? + val description: String? + val price: Int } diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/ui/BindingAdapters.java b/BasicSample/app/src/main/java/com/example/android/persistence/ui/BindingAdapters.kt similarity index 71% rename from BasicSample/app/src/main/java/com/example/android/persistence/ui/BindingAdapters.java rename to BasicSample/app/src/main/java/com/example/android/persistence/ui/BindingAdapters.kt index 0b9033551..74f748b76 100644 --- a/BasicSample/app/src/main/java/com/example/android/persistence/ui/BindingAdapters.java +++ b/BasicSample/app/src/main/java/com/example/android/persistence/ui/BindingAdapters.kt @@ -14,15 +14,16 @@ * limitations under the License. */ -package com.example.android.persistence.ui; +package com.example.android.persistence.ui -import android.databinding.BindingAdapter; -import android.view.View; +import android.databinding.BindingAdapter +import android.view.View -public class BindingAdapters { +object BindingAdapters { + @JvmStatic @BindingAdapter("visibleGone") - public static void showHide(View view, boolean show) { - view.setVisibility(show ? View.VISIBLE : View.GONE); + fun showHide(view: View, show: Boolean) { + view.visibility = if (show) View.VISIBLE else View.GONE } } \ No newline at end of file diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/ui/CommentAdapter.java b/BasicSample/app/src/main/java/com/example/android/persistence/ui/CommentAdapter.java deleted file mode 100644 index 24e0ecb5a..000000000 --- a/BasicSample/app/src/main/java/com/example/android/persistence/ui/CommentAdapter.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2017, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.persistence.ui; - -import android.databinding.DataBindingUtil; -import android.support.annotation.Nullable; -import android.support.v7.util.DiffUtil; -import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.ViewGroup; - -import com.example.android.persistence.databinding.CommentItemBinding; -import com.example.android.persistence.model.Comment; -import com.example.android.persistence.R; - -import java.util.List; -import java.util.Objects; - -public class CommentAdapter extends RecyclerView.Adapter { - - private List mCommentList; - - @Nullable - private final CommentClickCallback mCommentClickCallback; - - public CommentAdapter(@Nullable CommentClickCallback commentClickCallback) { - mCommentClickCallback = commentClickCallback; - } - - public void setCommentList(final List comments) { - if (mCommentList == null) { - mCommentList = comments; - notifyItemRangeInserted(0, comments.size()); - } else { - DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffUtil.Callback() { - @Override - public int getOldListSize() { - return mCommentList.size(); - } - - @Override - public int getNewListSize() { - return comments.size(); - } - - @Override - public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { - Comment old = mCommentList.get(oldItemPosition); - Comment comment = comments.get(newItemPosition); - return old.getId() == comment.getId(); - } - - @Override - public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { - Comment old = mCommentList.get(oldItemPosition); - Comment comment = comments.get(newItemPosition); - return old.getId() == comment.getId() - && old.getPostedAt() == comment.getPostedAt() - && old.getProductId() == comment.getProductId() - && Objects.equals(old.getText(), comment.getText()); - } - }); - mCommentList = comments; - diffResult.dispatchUpdatesTo(this); - } - } - - @Override - public CommentViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - CommentItemBinding binding = DataBindingUtil - .inflate(LayoutInflater.from(parent.getContext()), R.layout.comment_item, - parent, false); - binding.setCallback(mCommentClickCallback); - return new CommentViewHolder(binding); - } - - @Override - public void onBindViewHolder(CommentViewHolder holder, int position) { - holder.binding.setComment(mCommentList.get(position)); - holder.binding.executePendingBindings(); - } - - @Override - public int getItemCount() { - return mCommentList == null ? 0 : mCommentList.size(); - } - - static class CommentViewHolder extends RecyclerView.ViewHolder { - - final CommentItemBinding binding; - - CommentViewHolder(CommentItemBinding binding) { - super(binding.getRoot()); - this.binding = binding; - } - } -} diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/ui/CommentAdapter.kt b/BasicSample/app/src/main/java/com/example/android/persistence/ui/CommentAdapter.kt new file mode 100644 index 000000000..3e83bd585 --- /dev/null +++ b/BasicSample/app/src/main/java/com/example/android/persistence/ui/CommentAdapter.kt @@ -0,0 +1,81 @@ +/* + * Copyright 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.persistence.ui + +import android.databinding.DataBindingUtil +import android.support.v7.util.DiffUtil +import android.support.v7.widget.RecyclerView +import android.view.LayoutInflater +import android.view.ViewGroup + +import com.example.android.persistence.databinding.CommentItemBinding +import com.example.android.persistence.model.Comment +import com.example.android.persistence.R +import java.util.Objects + +class CommentAdapter(private val mCommentClickCallback: CommentClickCallback?) : RecyclerView.Adapter() { + + private var mCommentList: List? = null + + fun setCommentList(comments: List) { + if (mCommentList == null) { + mCommentList = comments + notifyItemRangeInserted(0, comments.size) + } else { + val diffResult = DiffUtil.calculateDiff(object : DiffUtil.Callback() { + + override fun getOldListSize() = mCommentList!!.size + + override fun getNewListSize() = comments.size + + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + val old = mCommentList!![oldItemPosition] + val comment = comments[newItemPosition] + return old.id == comment.id + } + + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + val old = mCommentList!![oldItemPosition] + val comment = comments[newItemPosition] + return old.id == comment.id + && old.postedAt === comment.postedAt + && old.productId == comment.productId + && old.text == comment.text + } + }) + mCommentList = comments + diffResult.dispatchUpdatesTo(this) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CommentViewHolder { + val binding = DataBindingUtil + .inflate(LayoutInflater.from(parent.context), R.layout.comment_item, + parent, false) + binding.callback = mCommentClickCallback + return CommentViewHolder(binding) + } + + override fun onBindViewHolder(holder: CommentViewHolder, position: Int) { + holder.binding.comment = mCommentList!![position] + holder.binding.executePendingBindings() + } + + override fun getItemCount() = mCommentList?.size ?: 0 + + inner class CommentViewHolder(val binding: CommentItemBinding) : RecyclerView.ViewHolder(binding.root) +} diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/ui/ProductClickCallback.java b/BasicSample/app/src/main/java/com/example/android/persistence/ui/CommentClickCallback.kt similarity index 78% rename from BasicSample/app/src/main/java/com/example/android/persistence/ui/ProductClickCallback.java rename to BasicSample/app/src/main/java/com/example/android/persistence/ui/CommentClickCallback.kt index b8f4c6b78..a52e790d4 100644 --- a/BasicSample/app/src/main/java/com/example/android/persistence/ui/ProductClickCallback.java +++ b/BasicSample/app/src/main/java/com/example/android/persistence/ui/CommentClickCallback.kt @@ -14,10 +14,10 @@ * limitations under the License. */ -package com.example.android.persistence.ui; +package com.example.android.persistence.ui -import com.example.android.persistence.model.Product; +import com.example.android.persistence.model.Comment -public interface ProductClickCallback { - void onClick(Product product); +interface CommentClickCallback { + fun onClick(comment: Comment) } diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/ui/ProductAdapter.java b/BasicSample/app/src/main/java/com/example/android/persistence/ui/ProductAdapter.java deleted file mode 100644 index e54c1ca2c..000000000 --- a/BasicSample/app/src/main/java/com/example/android/persistence/ui/ProductAdapter.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2017, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.persistence.ui; - -import android.databinding.DataBindingUtil; -import android.support.annotation.Nullable; -import android.support.v7.util.DiffUtil; -import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.ViewGroup; - -import com.example.android.persistence.databinding.ProductItemBinding; -import com.example.android.persistence.model.Product; -import com.example.android.persistence.R; - -import java.util.List; -import java.util.Objects; - -public class ProductAdapter extends RecyclerView.Adapter { - - List mProductList; - - @Nullable - private final ProductClickCallback mProductClickCallback; - - public ProductAdapter(@Nullable ProductClickCallback clickCallback) { - mProductClickCallback = clickCallback; - } - - public void setProductList(final List productList) { - if (mProductList == null) { - mProductList = productList; - notifyItemRangeInserted(0, productList.size()); - } else { - DiffUtil.DiffResult result = DiffUtil.calculateDiff(new DiffUtil.Callback() { - @Override - public int getOldListSize() { - return mProductList.size(); - } - - @Override - public int getNewListSize() { - return productList.size(); - } - - @Override - public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { - return mProductList.get(oldItemPosition).getId() == - productList.get(newItemPosition).getId(); - } - - @Override - public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { - Product product = productList.get(newItemPosition); - Product old = productList.get(oldItemPosition); - return product.getId() == old.getId() - && Objects.equals(product.getDescription(), old.getDescription()) - && Objects.equals(product.getName(), old.getName()) - && product.getPrice() == old.getPrice(); - } - }); - mProductList = productList; - result.dispatchUpdatesTo(this); - } - } - - @Override - public ProductViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - ProductItemBinding binding = DataBindingUtil - .inflate(LayoutInflater.from(parent.getContext()), R.layout.product_item, - parent, false); - binding.setCallback(mProductClickCallback); - return new ProductViewHolder(binding); - } - - @Override - public void onBindViewHolder(ProductViewHolder holder, int position) { - holder.binding.setProduct(mProductList.get(position)); - holder.binding.executePendingBindings(); - } - - @Override - public int getItemCount() { - return mProductList == null ? 0 : mProductList.size(); - } - - static class ProductViewHolder extends RecyclerView.ViewHolder { - - final ProductItemBinding binding; - - public ProductViewHolder(ProductItemBinding binding) { - super(binding.getRoot()); - this.binding = binding; - } - } -} diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/ui/ProductAdapter.kt b/BasicSample/app/src/main/java/com/example/android/persistence/ui/ProductAdapter.kt new file mode 100644 index 000000000..42757d895 --- /dev/null +++ b/BasicSample/app/src/main/java/com/example/android/persistence/ui/ProductAdapter.kt @@ -0,0 +1,78 @@ +/* + * Copyright 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.persistence.ui + +import android.databinding.DataBindingUtil +import android.support.v7.util.DiffUtil +import android.support.v7.widget.RecyclerView +import android.view.LayoutInflater +import android.view.ViewGroup + +import com.example.android.persistence.databinding.ProductItemBinding +import com.example.android.persistence.model.Product +import com.example.android.persistence.R +import java.util.Objects + +class ProductAdapter(private val mProductClickCallback: ProductClickCallback?) : RecyclerView.Adapter() { + + internal var mProductList: List? = null + + fun setProductList(productList: List) { + if (mProductList == null) { + mProductList = productList + notifyItemRangeInserted(0, productList.size) + } else { + val result = DiffUtil.calculateDiff(object : DiffUtil.Callback() { + + override fun getOldListSize() = mProductList!!.size + + override fun getNewListSize() = productList.size + + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) = + mProductList!![oldItemPosition].id == productList[newItemPosition].id + + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + val product = productList[newItemPosition] + val old = productList[oldItemPosition] + return product.id == old.id + && product.description == old.description + && product.name == old.name + && product.price == old.price + } + }) + mProductList = productList + result.dispatchUpdatesTo(this) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder { + val binding = DataBindingUtil + .inflate(LayoutInflater.from(parent.context), R.layout.product_item, + parent, false) + binding.callback = mProductClickCallback + return ProductViewHolder(binding) + } + + override fun onBindViewHolder(holder: ProductViewHolder, position: Int) { + holder.binding.product = mProductList!![position] + holder.binding.executePendingBindings() + } + + override fun getItemCount() = mProductList?.size ?: 0 + + inner class ProductViewHolder(val binding: ProductItemBinding) : RecyclerView.ViewHolder(binding.root) +} diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/model/Comment.java b/BasicSample/app/src/main/java/com/example/android/persistence/ui/ProductClickCallback.kt similarity index 77% rename from BasicSample/app/src/main/java/com/example/android/persistence/model/Comment.java rename to BasicSample/app/src/main/java/com/example/android/persistence/ui/ProductClickCallback.kt index c3483a409..fc1d11236 100644 --- a/BasicSample/app/src/main/java/com/example/android/persistence/model/Comment.java +++ b/BasicSample/app/src/main/java/com/example/android/persistence/ui/ProductClickCallback.kt @@ -14,13 +14,10 @@ * limitations under the License. */ -package com.example.android.persistence.model; +package com.example.android.persistence.ui -import java.util.Date; +import com.example.android.persistence.model.Product -public interface Comment { - int getId(); - int getProductId(); - String getText(); - Date getPostedAt(); +interface ProductClickCallback { + fun onClick(product: Product) } diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/viewmodel/ProductListViewModel.java b/BasicSample/app/src/main/java/com/example/android/persistence/viewmodel/ProductListViewModel.java deleted file mode 100644 index 8905b14f9..000000000 --- a/BasicSample/app/src/main/java/com/example/android/persistence/viewmodel/ProductListViewModel.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2017, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.persistence.viewmodel; - -import android.app.Application; -import android.arch.core.util.Function; -import android.arch.lifecycle.AndroidViewModel; -import android.arch.lifecycle.LiveData; -import android.arch.lifecycle.MutableLiveData; -import android.arch.lifecycle.Transformations; - -import com.example.android.persistence.db.DatabaseCreator; -import com.example.android.persistence.db.entity.ProductEntity; - -import java.util.List; - -public class ProductListViewModel extends AndroidViewModel { - - private static final MutableLiveData ABSENT = new MutableLiveData(); - { - //noinspection unchecked - ABSENT.setValue(null); - } - - private final LiveData> mObservableProducts; - - public ProductListViewModel(Application application) { - super(application); - - final DatabaseCreator databaseCreator = DatabaseCreator.getInstance(this.getApplication()); - - LiveData databaseCreated = databaseCreator.isDatabaseCreated(); - mObservableProducts = Transformations.switchMap(databaseCreated, - new Function>>() { - @Override - public LiveData> apply(Boolean isDbCreated) { - if (!Boolean.TRUE.equals(isDbCreated)) { // Not needed here, but watch out for null - //noinspection unchecked - return ABSENT; - } else { - //noinspection ConstantConditions - return databaseCreator.getDatabase().productDao().loadAllProducts(); - } - } - }); - - databaseCreator.createDb(this.getApplication()); - } - - /** - * Expose the LiveData Products query so the UI can observe it. - */ - public LiveData> getProducts() { - return mObservableProducts; - } -} diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/viewmodel/ProductListViewModel.kt b/BasicSample/app/src/main/java/com/example/android/persistence/viewmodel/ProductListViewModel.kt new file mode 100644 index 000000000..1738396f6 --- /dev/null +++ b/BasicSample/app/src/main/java/com/example/android/persistence/viewmodel/ProductListViewModel.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.persistence.viewmodel + +import android.app.Application +import android.arch.core.util.Function +import android.arch.lifecycle.AndroidViewModel +import android.arch.lifecycle.LiveData +import android.arch.lifecycle.MutableLiveData +import android.arch.lifecycle.Transformations + +import com.example.android.persistence.db.DatabaseCreator +import com.example.android.persistence.db.entity.ProductEntity + +class ProductListViewModel(application: Application) : AndroidViewModel(application) { + + private val ABSENT = MutableLiveData>() + + /** + * Expose the LiveData Products query so the UI can observe it. + */ + val products: LiveData> + + init { + + ABSENT.value = null + + val databaseCreator = DatabaseCreator.getInstance(this.getApplication()) + + val databaseCreated = databaseCreator.isDatabaseCreated + products = Transformations.switchMap(databaseCreated + ) { isDbCreated -> + if (java.lang.Boolean.TRUE != isDbCreated) { // Not needed here, but watch out for null + + ABSENT + } else { + + databaseCreator.database!!.productDao().loadAllProducts() + } + } + + databaseCreator.createDb(this.getApplication()) + } +} diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/viewmodel/ProductViewModel.java b/BasicSample/app/src/main/java/com/example/android/persistence/viewmodel/ProductViewModel.java deleted file mode 100644 index 08534c3af..000000000 --- a/BasicSample/app/src/main/java/com/example/android/persistence/viewmodel/ProductViewModel.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2017, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.persistence.viewmodel; - -import android.app.Application; -import android.arch.core.util.Function; -import android.arch.lifecycle.AndroidViewModel; -import android.arch.lifecycle.LiveData; -import android.arch.lifecycle.MutableLiveData; -import android.arch.lifecycle.Transformations; -import android.arch.lifecycle.ViewModel; -import android.arch.lifecycle.ViewModelProvider; -import android.databinding.ObservableField; -import android.support.annotation.NonNull; - -import com.example.android.persistence.db.DatabaseCreator; -import com.example.android.persistence.db.entity.CommentEntity; -import com.example.android.persistence.db.entity.ProductEntity; - -import java.util.List; - -public class ProductViewModel extends AndroidViewModel { - - private static final MutableLiveData ABSENT = new MutableLiveData(); - { - //noinspection unchecked - ABSENT.setValue(null); - } - - private final LiveData mObservableProduct; - - public ObservableField product = new ObservableField<>(); - - private final int mProductId; - - private final LiveData> mObservableComments; - - public ProductViewModel(@NonNull Application application, - final int productId) { - super(application); - mProductId = productId; - - final DatabaseCreator databaseCreator = DatabaseCreator.getInstance(this.getApplication()); - - mObservableComments = Transformations.switchMap(databaseCreator.isDatabaseCreated(), new Function>>() { - @Override - public LiveData> apply(Boolean isDbCreated) { - if (!isDbCreated) { - //noinspection unchecked - return ABSENT; - } else { - //noinspection ConstantConditions - return databaseCreator.getDatabase().commentDao().loadComments(mProductId); - } - } - }); - - mObservableProduct = Transformations.switchMap(databaseCreator.isDatabaseCreated(), new Function>() { - @Override - public LiveData apply(Boolean isDbCreated) { - if (!isDbCreated) { - //noinspection unchecked - return ABSENT; - } else { - //noinspection ConstantConditions - return databaseCreator.getDatabase().productDao().loadProduct(mProductId); - } - } - }); - - databaseCreator.createDb(this.getApplication()); - - } - /** - * Expose the LiveData Comments query so the UI can observe it. - */ - public LiveData> getComments() { - return mObservableComments; - } - - public LiveData getObservableProduct() { - return mObservableProduct; - } - - public void setProduct(ProductEntity product) { - this.product.set(product); - } - - /** - * A creator is used to inject the product ID into the ViewModel - *

- * This creator is to showcase how to inject dependencies into ViewModels. It's not - * actually necessary in this case, as the product ID can be passed in a public method. - */ - public static class Factory extends ViewModelProvider.NewInstanceFactory { - - @NonNull - private final Application mApplication; - - private final int mProductId; - - public Factory(@NonNull Application application, int productId) { - mApplication = application; - mProductId = productId; - } - - @Override - public T create(Class modelClass) { - //noinspection unchecked - return (T) new ProductViewModel(mApplication, mProductId); - } - } -} diff --git a/BasicSample/app/src/main/java/com/example/android/persistence/viewmodel/ProductViewModel.kt b/BasicSample/app/src/main/java/com/example/android/persistence/viewmodel/ProductViewModel.kt new file mode 100644 index 000000000..9286183e1 --- /dev/null +++ b/BasicSample/app/src/main/java/com/example/android/persistence/viewmodel/ProductViewModel.kt @@ -0,0 +1,86 @@ +/* + * Copyright 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.persistence.viewmodel + +import android.app.Application +import android.arch.lifecycle.* +import android.databinding.ObservableField +import com.example.android.persistence.db.DatabaseCreator +import com.example.android.persistence.db.entity.CommentEntity +import com.example.android.persistence.db.entity.ProductEntity + +class ProductViewModel(application: Application, + private val mProductId: Int) : AndroidViewModel(application) { + + private val ABSENT = MutableLiveData>() + + val observableProduct: LiveData + + var product = ObservableField() + + /** + * Expose the LiveData Comments query so the UI can observe it. + */ + val comments: LiveData> + + init { + + ABSENT.value = null + + val databaseCreator = DatabaseCreator.getInstance(this.getApplication()) + + comments = Transformations.switchMap(databaseCreator.isDatabaseCreated) { isDbCreated -> + if (!isDbCreated) { + + ABSENT as LiveData> + } else { + + databaseCreator.database!!.commentDao().loadComments(mProductId) + } + } + + observableProduct = Transformations.switchMap(databaseCreator.isDatabaseCreated) { isDbCreated -> + if (!isDbCreated) { + + ABSENT as LiveData + } else { + + databaseCreator.database!!.productDao().loadProduct(mProductId) + } + } + + databaseCreator.createDb(this.getApplication()) + + } + + fun setProduct(product: ProductEntity?) { + this.product.set(product) + } + + /** + * A creator is used to inject the product ID into the ViewModel + * + * + * This creator is to showcase how to inject dependencies into ViewModels. It's not + * actually necessary in this case, as the product ID can be passed in a public method. + */ + class Factory(private val mApplication: Application, private val mProductId: Int) : ViewModelProvider.NewInstanceFactory() { + + override fun create(modelClass: Class): T = + ProductViewModel(mApplication, mProductId) as T + } +} diff --git a/BasicSample/build.gradle b/BasicSample/build.gradle index c1d295778..a10a1a365 100644 --- a/BasicSample/build.gradle +++ b/BasicSample/build.gradle @@ -17,16 +17,19 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { + ext.kotlin_version = '1.1.4-2' repositories { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.1' + classpath 'com.android.tools.build:gradle:3.0.0-beta2' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } +apply plugin: 'kotlin' allprojects { repositories { @@ -37,10 +40,6 @@ allprojects { } } -task clean(type: Delete) { - delete rootProject.buildDir -} - ext { buildToolsVersion = "25.0.2" supportLibVersion = "25.3.1" @@ -49,4 +48,20 @@ ext { espressoVersion = "2.2.2" archLifecycleVersion = "1.0.0-alpha1" archRoomVersion = "1.0.0-alpha1" +} +repositories { + mavenCentral() +} +dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" +} +compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} +compileTestKotlin { + kotlinOptions { + jvmTarget = "1.8" + } } \ No newline at end of file diff --git a/BasicSample/gradle/wrapper/gradle-wrapper.properties b/BasicSample/gradle/wrapper/gradle-wrapper.properties index c196a492f..99994d2d1 100644 --- a/BasicSample/gradle/wrapper/gradle-wrapper.properties +++ b/BasicSample/gradle/wrapper/gradle-wrapper.properties @@ -1,22 +1,6 @@ -# -# Copyright 2017, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -#Mon Apr 24 18:19:01 CEST 2017 +#Sun Aug 20 21:31:50 KST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-milestone-1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-rc-1-all.zip