diff --git a/.idea/modules.xml b/.idea/modules.xml index bf4147c..816a809 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -3,8 +3,11 @@ + + + \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..84db3e7 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,18 @@ +language: android + +android: + components: + - tools + - platform-tools + - build-tools-25.0.2 + - android-25 + - extra-android-m2repository + - extra-google-google_play_services + +jdk: + - oraclejdk8 + +notifications: + email: false + +script: ./gradlew assemble check diff --git a/mobile/src/main/java/io/github/marktony/espresso/data/source/CompaniesRepository.java b/mobile/src/main/java/io/github/marktony/espresso/data/source/CompaniesRepository.java index ea0808a..97c7ccb 100644 --- a/mobile/src/main/java/io/github/marktony/espresso/data/source/CompaniesRepository.java +++ b/mobile/src/main/java/io/github/marktony/espresso/data/source/CompaniesRepository.java @@ -1,3 +1,19 @@ +/* + * Copyright(c) 2017 lizhaotailang + * + * 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 io.github.marktony.espresso.data.source; import android.support.annotation.NonNull; @@ -52,4 +68,4 @@ public Observable> searchCompanies(@NonNull String keyWords) { return localDataSource.searchCompanies(keyWords); } -} \ No newline at end of file +} diff --git a/mobile/src/main/java/io/github/marktony/espresso/data/source/PackagesRepository.java b/mobile/src/main/java/io/github/marktony/espresso/data/source/PackagesRepository.java index f7819d2..e736f86 100644 --- a/mobile/src/main/java/io/github/marktony/espresso/data/source/PackagesRepository.java +++ b/mobile/src/main/java/io/github/marktony/espresso/data/source/PackagesRepository.java @@ -1,3 +1,19 @@ +/* + * Copyright(c) 2017 lizhaotailang + * + * 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 io.github.marktony.espresso.data.source; import android.support.annotation.NonNull; @@ -40,8 +56,6 @@ public class PackagesRepository implements PackagesDataSource { private Map cachedPackages; - private Package cachePackage = null; - // Prevent direct instantiation private PackagesRepository(@NonNull PackagesDataSource packagesRemoteDataSource, @NonNull PackagesDataSource packagesLocalDataSource) { @@ -158,7 +172,6 @@ public void savePackage(@NonNull Package pack) { */ @Override public void deletePackage(@NonNull String packageId) { - cachePackage = getPackageWithNumber(packageId); packagesLocalDataSource.deletePackage(packageId); cachedPackages.remove(packageId); } @@ -316,4 +329,4 @@ public void accept(Package aPackage) throws Exception { }); } -} \ No newline at end of file +} diff --git a/mobile/src/main/java/io/github/marktony/espresso/data/source/local/CompaniesLocalDataSource.java b/mobile/src/main/java/io/github/marktony/espresso/data/source/local/CompaniesLocalDataSource.java index 0c947e7..b6d2b31 100644 --- a/mobile/src/main/java/io/github/marktony/espresso/data/source/local/CompaniesLocalDataSource.java +++ b/mobile/src/main/java/io/github/marktony/espresso/data/source/local/CompaniesLocalDataSource.java @@ -20,14 +20,11 @@ import android.support.annotation.Nullable; import java.util.List; -import java.util.concurrent.Callable; import io.github.marktony.espresso.data.Company; import io.github.marktony.espresso.data.source.CompaniesDataSource; import io.github.marktony.espresso.realm.RealmHelper; import io.reactivex.Observable; -import io.reactivex.ObservableSource; -import io.reactivex.functions.Function; import io.realm.Case; import io.realm.Realm; import io.realm.Sort; @@ -55,31 +52,18 @@ public static CompaniesLocalDataSource getInstance() { @Override public Observable> getCompanies() { - return Observable.fromCallable(new Callable>() { - @Override - public List call() throws Exception { - Realm rlm = RealmHelper.newRealmInstance(); - List companyList = rlm.copyFromRealm(rlm.where(Company.class) - .findAllSorted("alphabet", Sort.ASCENDING)); - rlm.close(); - return companyList; - } - }); + Realm rlm = RealmHelper.newRealmInstance(); + return Observable + .fromIterable(rlm.copyFromRealm(rlm.where(Company.class).findAllSorted("alphabet", Sort.ASCENDING))) + .toList() + .toObservable(); } @Override - public Observable getCompany(@NonNull final String companyId) { - return Observable.fromCallable(new Callable() { - @Override - public Company call() throws Exception { - Realm rlm = RealmHelper.newRealmInstance(); - Company company = rlm.copyFromRealm(rlm.where(Company.class) - .equalTo("id", companyId) - .findFirst()); - rlm.close(); - return company; - } - }); + public Observable getCompany(@NonNull String companyId) { + Realm rlm = RealmHelper.newRealmInstance(); + return Observable + .just(rlm.copyFromRealm(rlm.where(Company.class).equalTo("id", companyId).findFirst())); } @Override @@ -734,17 +718,11 @@ public void initData() { } @Override - public Observable> searchCompanies(@NonNull final String keyWords) { - - return Observable.fromCallable(new Callable>() { - @Override - public List call() throws Exception { - Realm rlm = RealmHelper.newRealmInstance(); - List companies = rlm.copyFromRealm(rlm.where(Company.class) - .like( - "name", - "*" + keyWords + "*", - Case.INSENSITIVE) + public Observable> searchCompanies(@NonNull String keyWords) { + Realm rlm = RealmHelper.newRealmInstance(); + List results = rlm.copyFromRealm( + rlm.where(Company.class) + .like("name","*" + keyWords + "*", Case.INSENSITIVE) .or() .like("tel", "*" + keyWords + "*", Case.INSENSITIVE) .or() @@ -752,10 +730,9 @@ public List call() throws Exception { .or() .like("alphabet", "*" + keyWords + "*", Case.INSENSITIVE) .findAllSorted("alphabet", Sort.ASCENDING)); - rlm.close(); - return companies; - } - }); + return Observable.fromIterable(results) + .toList() + .toObservable(); } } \ No newline at end of file diff --git a/mobile/src/main/java/io/github/marktony/espresso/data/source/local/PackagesLocalDataSource.java b/mobile/src/main/java/io/github/marktony/espresso/data/source/local/PackagesLocalDataSource.java index c2e220f..e646803 100644 --- a/mobile/src/main/java/io/github/marktony/espresso/data/source/local/PackagesLocalDataSource.java +++ b/mobile/src/main/java/io/github/marktony/espresso/data/source/local/PackagesLocalDataSource.java @@ -20,7 +20,6 @@ import android.support.annotation.Nullable; import java.util.List; -import java.util.concurrent.Callable; import io.github.marktony.espresso.data.Package; import io.github.marktony.espresso.data.source.PackagesDataSource; @@ -65,16 +64,10 @@ public static void destroyInstance() { */ @Override public Observable> getPackages() { - return Observable.fromCallable(new Callable>() { - @Override - public List call() throws Exception { - Realm rlm = RealmHelper.newRealmInstance(); - List packageList = rlm.copyFromRealm(rlm.where(Package.class) - .findAllSorted("timestamp", Sort.DESCENDING)); - rlm.close(); - return packageList; - } - }); + Realm rlm = RealmHelper.newRealmInstance(); + + return Observable.just(rlm.copyFromRealm(rlm.where(Package.class) + .findAllSorted("timestamp", Sort.DESCENDING))); } /** @@ -85,18 +78,11 @@ public List call() throws Exception { * @return The observable package from database. */ @Override - public Observable getPackage(@NonNull final String packNumber) { - return Observable.fromCallable(new Callable() { - @Override - public Package call() throws Exception { - Realm rlm = RealmHelper.newRealmInstance(); - Package aPackage = rlm.copyFromRealm(rlm.where(Package.class) - .equalTo("number", packNumber) - .findFirst()); - rlm.close(); - return aPackage; - } - }); + public Observable getPackage(@NonNull String packNumber) { + Realm rlm = RealmHelper.newRealmInstance(); + return Observable.just(rlm.copyFromRealm(rlm.where(Package.class) + .equalTo("number", packNumber) + .findFirst())); } /** @@ -201,7 +187,6 @@ public boolean isPackageExist(@NonNull String packageId) { RealmResults results = rlm.where(Package.class) .equalTo("number", packageId) .findAll(); - rlm.close(); return (results != null) && (!results.isEmpty()); } @@ -221,32 +206,20 @@ public void updatePackageName(@NonNull String packageId, @NonNull String name) { } @Override - public Observable> searchPackages(@NonNull - final String keyWords) { - - return Observable.fromCallable(new Callable>() { - @Override - public List call() throws Exception { - Realm rlm = RealmHelper.newRealmInstance(); - List packages = rlm.copyFromRealm(rlm.where(Package.class) - .like( - "name", - "*" + keyWords + "*", - Case.INSENSITIVE) + public Observable> searchPackages(@NonNull String keyWords) { + Realm rlm = RealmHelper.newRealmInstance(); + return Observable.fromIterable(rlm.copyFromRealm( + rlm.where(Package.class) + .like("name", "*" + keyWords + "*", Case.INSENSITIVE) .or() .like("companyChineseName", "*" + keyWords + "*", Case.INSENSITIVE) .or() - .like( - "company", - "*" + keyWords + "*", - Case.INSENSITIVE) + .like("company", "*" + keyWords + "*", Case.INSENSITIVE) .or() .like("number", "*" + keyWords + "*", Case.INSENSITIVE) - .findAll()); - rlm.close(); - return packages; - } - }); + .findAll())) + .toList() + .toObservable(); } } diff --git a/mobile/src/main/java/io/github/marktony/espresso/data/source/remote/PackagesRemoteDataSource.java b/mobile/src/main/java/io/github/marktony/espresso/data/source/remote/PackagesRemoteDataSource.java index 654004d..82a2e72 100644 --- a/mobile/src/main/java/io/github/marktony/espresso/data/source/remote/PackagesRemoteDataSource.java +++ b/mobile/src/main/java/io/github/marktony/espresso/data/source/remote/PackagesRemoteDataSource.java @@ -1,3 +1,19 @@ +/* + * Copyright(c) 2017 lizhaotailang + * + * 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 io.github.marktony.espresso.data.source.remote; import android.support.annotation.NonNull; @@ -7,7 +23,6 @@ import io.github.marktony.espresso.data.Package; import io.github.marktony.espresso.data.source.PackagesDataSource; -import io.github.marktony.espresso.realm.RealmHelper; import io.github.marktony.espresso.retrofit.RetrofitClient; import io.github.marktony.espresso.retrofit.RetrofitService; import io.reactivex.Observable; @@ -19,6 +34,8 @@ import io.realm.Realm; import io.realm.RealmConfiguration; +import static io.github.marktony.espresso.realm.RealmHelper.DATABASE_NAME; + /** * Created by lizhaotailang on 2017/3/7. * Implementation of the data source that adds a latency simulating network. @@ -81,7 +98,10 @@ public void deletePackage(@NonNull String packageId) { public Observable> refreshPackages() { // It is necessary to build a new realm instance // in a different thread. - Realm realm = RealmHelper.newRealmInstance(); + Realm realm = Realm.getInstance(new RealmConfiguration.Builder() + .deleteRealmIfMigrationNeeded() + .name(DATABASE_NAME) + .build()); return Observable.fromIterable(realm.copyFromRealm(realm.where(Package.class).findAll())) .subscribeOn(Schedulers.io()) @@ -105,7 +125,10 @@ public ObservableSource apply(Package aPackage) throws Exception { public Observable refreshPackage(@NonNull String packageId) { // It is necessary to build a new realm instance // in a different thread. - Realm realm = RealmHelper.newRealmInstance(); + Realm realm = Realm.getInstance(new RealmConfiguration.Builder() + .deleteRealmIfMigrationNeeded() + .name(DATABASE_NAME) + .build()); // Set a copy rather than use the raw data. final Package p = realm.copyFromRealm(realm.where(Package.class) .equalTo("number", packageId) @@ -131,7 +154,10 @@ public void accept(Package aPackage) throws Exception { if (aPackage != null && aPackage.getData() != null) { // It is necessary to build a new realm instance // in a different thread. - Realm rlm = RealmHelper.newRealmInstance(); + Realm rlm = Realm.getInstance(new RealmConfiguration.Builder() + .deleteRealmIfMigrationNeeded() + .name(DATABASE_NAME) + .build()); // Only when the origin data is null or the origin // data's size is less than the latest data's size diff --git a/mobile/src/main/java/io/github/marktony/espresso/mvp/addpackage/AddPackageFragment.java b/mobile/src/main/java/io/github/marktony/espresso/mvp/addpackage/AddPackageFragment.java index d91bb9d..3abacf1 100644 --- a/mobile/src/main/java/io/github/marktony/espresso/mvp/addpackage/AddPackageFragment.java +++ b/mobile/src/main/java/io/github/marktony/espresso/mvp/addpackage/AddPackageFragment.java @@ -23,6 +23,7 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; +import android.graphics.Rect; import android.net.Uri; import android.os.Bundle; import android.provider.Settings; @@ -33,6 +34,7 @@ import android.support.design.widget.TextInputEditText; import android.support.v4.app.Fragment; import android.support.v4.content.ContextCompat; +import android.support.v4.widget.NestedScrollView; import android.support.v7.app.AlertDialog; import android.support.v7.widget.AppCompatTextView; import android.support.v7.widget.Toolbar; @@ -40,6 +42,7 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.view.ViewTreeObserver; import android.view.inputmethod.InputMethodManager; import android.widget.ProgressBar; @@ -67,6 +70,7 @@ public class AddPackageFragment extends Fragment private AppCompatTextView textViewScanCode; private FloatingActionButton fab; private ProgressBar progressBar; + private NestedScrollView scrollView; private AddPackageContract.Presenter presenter; @@ -95,6 +99,8 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, initViews(view); + addLayoutListener(scrollView, editTextName); + fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -160,6 +166,32 @@ public void onPause() { presenter.unsubscribe(); } + /** + * Scroll the screen to avoid edit text being covered by imm such as the soft keyboard. + * It is better to set the height as 150 because some devices + * has the navigation bar. The height 100 might not trigger the scrolling action. + * @param main The scroll view. + * @param scroll The view to show. + */ + private void addLayoutListener(final View main, final View scroll) { + main.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + Rect rect = new Rect(); + main.getWindowVisibleDisplayFrame(rect); + int mainInvisibleHeight = main.getRootView().getHeight() - rect.bottom; + if (mainInvisibleHeight > 150) { + int[] location = new int[2]; + scroll.getLocationInWindow(location); + int scrollHeight = (location[1] + scroll.getHeight()) - rect.bottom; + main.scrollTo(0, scrollHeight); + } else { + main.scrollTo(0, 0); + } + } + }); + } + @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); @@ -185,6 +217,8 @@ public void initViews(View view) { textViewScanCode = (AppCompatTextView) view.findViewById(R.id.textViewScanCode); fab = (FloatingActionButton) view.findViewById(R.id.fab); progressBar = (ProgressBar) view.findViewById(R.id.progressBar); + scrollView = (NestedScrollView) view.findViewById(R.id.scrollView); + } /** diff --git a/mobile/src/main/java/io/github/marktony/espresso/ui/onboarding/OnboardingActivity.java b/mobile/src/main/java/io/github/marktony/espresso/ui/onboarding/OnboardingActivity.java index cd13200..f3a09da 100644 --- a/mobile/src/main/java/io/github/marktony/espresso/ui/onboarding/OnboardingActivity.java +++ b/mobile/src/main/java/io/github/marktony/espresso/ui/onboarding/OnboardingActivity.java @@ -155,7 +155,7 @@ private void updateIndicators(int position) { } } - private Handler handler = new Handler() { + private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { diff --git a/mobile/src/main/java/io/github/marktony/espresso/zxing/utils/InactivityTimer.java b/mobile/src/main/java/io/github/marktony/espresso/zxing/utils/InactivityTimer.java index 3aad2cb..106b04d 100644 --- a/mobile/src/main/java/io/github/marktony/espresso/zxing/utils/InactivityTimer.java +++ b/mobile/src/main/java/io/github/marktony/espresso/zxing/utils/InactivityTimer.java @@ -24,7 +24,6 @@ import android.content.IntentFilter; import android.os.AsyncTask; import android.os.BatteryManager; -import android.os.Build; import android.util.Log; /**