diff --git a/build.gradle b/build.gradle index 49e1625..a42d6bc 100644 --- a/build.gradle +++ b/build.gradle @@ -26,9 +26,19 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:appcompat-v7:23.1.0' - compile 'com.facebook.fresco:fbcore:0.7.0' - compile 'io.reactivex:rxandroid:1.0.1' + compile project(':libraries:core') + + provided 'com.android.support:appcompat-v7:23.1.0' + provided 'io.reactivex:rxandroid:1.0.1' + + provided('com.google.http-client:google-http-client-android:1.20.0') { + exclude(group: 'org.apache.httpcomponents', module: 'httpclient') + } + provided('com.google.http-client:google-http-client-jackson2:1.20.0') { + exclude(group: 'org.apache.httpcomponents', module: 'httpclient') + } + provided 'com.squareup.okhttp:okhttp:2.5.0' + provided 'com.facebook.fresco:fbcore:0.7.0' } apply from: "${rootDir}/libraries/BuildScripts/gradle/staticAnalysis.gradle" diff --git a/src/main/java/org/roboswag/components/navigation/BaseFragment.java b/src/main/java/org/roboswag/components/navigation/BaseFragment.java index 2c98b4a..148538b 100644 --- a/src/main/java/org/roboswag/components/navigation/BaseFragment.java +++ b/src/main/java/org/roboswag/components/navigation/BaseFragment.java @@ -26,13 +26,15 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; +import android.view.Menu; +import android.view.MenuInflater; import android.view.View; /** * Created by Gavriil Sitnikov on 21/10/2015. * TODO: fill description */ -public abstract class BaseFragment extends Fragment +public abstract class BaseFragment extends Fragment implements OnFragmentStartedListener { @Nullable @@ -118,6 +120,11 @@ public abstract class BaseFragment return result; } + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + } + /* Raises when ActionBar home button pressed */ public boolean onHomePressed() { FragmentManager fragmentManager = getChildFragmentManager(); @@ -178,7 +185,7 @@ public abstract class BaseFragment viewHolder.onDestroy(); } - public class ViewHolder { + public class ViewController { private final Context context; private final Handler postHandler = new Handler(); @@ -194,7 +201,7 @@ public abstract class BaseFragment return context; } - public ViewHolder(@NonNull View view){ + public ViewController(@NonNull View view) { context = view.getContext(); } diff --git a/src/main/java/org/roboswag/components/requests/AbstractGetJsonRequest.java b/src/main/java/org/roboswag/components/requests/AbstractGetJsonRequest.java new file mode 100644 index 0000000..5b4c1fe --- /dev/null +++ b/src/main/java/org/roboswag/components/requests/AbstractGetJsonRequest.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov) + * + * This file is part of RoboSwag library. + * + * 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 org.roboswag.components.requests; + +import android.support.annotation.NonNull; + +import com.squareup.okhttp.Request; + +import java.io.IOException; + +/** + * Created by Gavriil Sitnikov on 07/14. + * Get request that returns data in JSON format + */ +public abstract class AbstractGetJsonRequest extends AbstractJsonRequest { + + protected AbstractGetJsonRequest(@NonNull final Class responseResultType) { + super(responseResultType); + } + + @NonNull + @Override + protected Request.Builder createHttpRequest() throws IOException { + return super.createHttpRequest().get(); + } + +} diff --git a/src/main/java/org/roboswag/components/requests/AbstractHttpRequest.java b/src/main/java/org/roboswag/components/requests/AbstractHttpRequest.java new file mode 100644 index 0000000..442cf8b --- /dev/null +++ b/src/main/java/org/roboswag/components/requests/AbstractHttpRequest.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov) + * + * This file is part of RoboSwag library. + * + * 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 org.roboswag.components.requests; + +import android.support.annotation.NonNull; +import android.util.Log; + +import com.google.api.client.http.GenericUrl; +import com.google.api.client.util.Charsets; +import com.google.api.client.util.ObjectParser; +import com.squareup.okhttp.Call; +import com.squareup.okhttp.MediaType; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.RequestBody; +import com.squareup.okhttp.Response; +import com.squareup.okhttp.ResponseBody; + +import org.roboswag.core.log.Lc; +import org.roboswag.core.log.LcHelper; +import org.roboswag.core.utils.ShouldNotHappenException; +import org.roboswag.core.utils.StringUtils; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.Charset; + +import okio.Buffer; +import rx.Observable; +import rx.schedulers.Schedulers; + +/** + * Created by Gavriil Sitnikov on 13/11/2015. + * TODO: fill description + */ +public abstract class AbstractHttpRequest { + + private static final String CACHE_PARAMETER_SEPARATOR = "#"; + private static final int CACHE_MAX_KEY_SIZE = 128; + + @NonNull + private final Class responseResultType; + + private Request request; + private Call call; + + protected AbstractHttpRequest(@NonNull final Class responseResultType) { + this.responseResultType = responseResultType; + } + + @NonNull + public Class getResponseResultType() { + return responseResultType; + } + + /* Returns data parser */ + protected abstract ObjectParser getParser() throws Exception; + + @NonNull + protected abstract String getUrl(); + + protected void setupUrlParameters(@NonNull final GenericUrl url) { + // to be overridden. default does nothing + } + + @NonNull + protected OkHttpClient createHttpClient() { + return new OkHttpClient(); + } + + @NonNull + protected Request.Builder createHttpRequest() throws IOException { + final GenericUrl genericUrl = new GenericUrl(getUrl()); + setupUrlParameters(genericUrl); + return new Request.Builder().url(genericUrl.build()); + } + + @NonNull + private Request getRequest() throws IOException { + if (request == null) { + request = createHttpRequest().build(); + } + return request; + } + + public void cancel() { + if (call != null && !call.isCanceled()) { + call.cancel(); + } + } + + @NonNull + public T executeSync() throws Exception { + final Request request = getRequest(); + if (LcHelper.getLogLevel() <= Log.DEBUG) { + Lc.d("Url requested: %s\n%s", request.url(), requestBodyToString(request)); + } + call = createHttpClient().newCall(request); + final Response response = call.execute(); + final ResponseBody responseBody = response.body(); + final byte[] bytes = responseBody.bytes(); + final Charset charset = getCharset(responseBody); + if (LcHelper.getLogLevel() <= Log.DEBUG) { + Lc.d("Response for: %s has code %s and content: %s", request.url(), response.code(), new String(bytes, charset)); + } + final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); + T result = getParser().parseAndClose(byteArrayInputStream, charset, responseResultType); + result = handleResponse(result); + return result; + } + + @NonNull + public Observable execute() { + return Observable.create(subscriber -> { + try { + subscriber.onNext(executeSync()); + subscriber.onCompleted(); + } catch (Exception e) { + subscriber.onError(e); + } + }).subscribeOn(Schedulers.io()); + } + + @NonNull + private Charset getCharset(final ResponseBody responseBody) { + final MediaType contentType = responseBody.contentType(); + return contentType == null ? Charsets.UTF_8 : contentType.charset(Charsets.UTF_8); + } + + private String requestBodyToString(@NonNull final Request request) throws IOException { + final RequestBody body = request.newBuilder().build().body(); + if (body == null) { + return ""; + } + final Buffer buffer = new Buffer(); + body.writeTo(buffer); + return buffer.readUtf8(); + } + + /* Handle response. Use it to do something after request successfully executes */ + @NonNull + protected T handleResponse(final T response) throws Exception { + return response; + } + + @NonNull + public String getCacheKey() { + final StringBuilder fileNameSafeCacheKey = new StringBuilder(); + try { + final Request request = getRequest(); + fileNameSafeCacheKey.append(URLEncoder.encode(request.urlString(), "UTF-8").replace("%", CACHE_PARAMETER_SEPARATOR)); + fileNameSafeCacheKey.append(CACHE_PARAMETER_SEPARATOR).append(request.headers()); + if (request.body() != null) { + fileNameSafeCacheKey.append(CACHE_PARAMETER_SEPARATOR).append(requestBodyToString(request)); + } + } catch (final Exception e) { + throw new ShouldNotHappenException(e); + } + final String cacheKeyMd5 = StringUtils.md5(fileNameSafeCacheKey.toString()); + final int length = fileNameSafeCacheKey.length(); + return fileNameSafeCacheKey.substring(Math.max(0, length - CACHE_MAX_KEY_SIZE), length) + CACHE_PARAMETER_SEPARATOR + cacheKeyMd5; + } + +} \ No newline at end of file diff --git a/src/main/java/org/roboswag/components/requests/AbstractJsonContentPostJsonRequest.java b/src/main/java/org/roboswag/components/requests/AbstractJsonContentPostJsonRequest.java new file mode 100644 index 0000000..18ccc37 --- /dev/null +++ b/src/main/java/org/roboswag/components/requests/AbstractJsonContentPostJsonRequest.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov) + * + * This file is part of RoboSwag library. + * + * 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 org.roboswag.components.requests; + +import android.support.annotation.NonNull; + +import com.google.api.client.http.AbstractHttpContent; +import com.google.api.client.http.json.JsonHttpContent; + +/** + * Created by Gavriil Sitnikov on 07/14. + * Post request that includes JSON data as content and returns data in JSON format + */ +public abstract class AbstractJsonContentPostJsonRequest extends AbstractPostJsonRequest { + + @NonNull + @Override + protected AbstractHttpContent getContent() { + return new JsonHttpContent(DEFAULT_JSON_FACTORY, getContentObject()); + } + + protected AbstractJsonContentPostJsonRequest(@NonNull final Class responseResultType) { + super(responseResultType); + } + + /* Returns content object to store in JSON format */ + @NonNull + protected abstract Object getContentObject(); + +} \ No newline at end of file diff --git a/src/main/java/org/roboswag/components/requests/AbstractJsonRequest.java b/src/main/java/org/roboswag/components/requests/AbstractJsonRequest.java new file mode 100644 index 0000000..88f95bd --- /dev/null +++ b/src/main/java/org/roboswag/components/requests/AbstractJsonRequest.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov) + * + * This file is part of RoboSwag library. + * + * 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 org.roboswag.components.requests; + +import android.support.annotation.NonNull; + +import com.google.api.client.json.JsonFactory; +import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.client.util.ObjectParser; + +/** + * Created by Gavriil Sitnikov on 07/14. + * Request that returns data in JSON format + */ +public abstract class AbstractJsonRequest extends AbstractHttpRequest { + + protected static final JsonFactory DEFAULT_JSON_FACTORY = new JacksonFactory(); + + @NonNull + @Override + protected ObjectParser getParser() { + return DEFAULT_JSON_FACTORY.createJsonObjectParser(); + } + + protected AbstractJsonRequest(@NonNull final Class responseResultType) { + super(responseResultType); + } + +} \ No newline at end of file diff --git a/src/main/java/org/roboswag/components/requests/AbstractPostJsonRequest.java b/src/main/java/org/roboswag/components/requests/AbstractPostJsonRequest.java new file mode 100644 index 0000000..d3d82b8 --- /dev/null +++ b/src/main/java/org/roboswag/components/requests/AbstractPostJsonRequest.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov) + * + * This file is part of RoboSwag library. + * + * 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 org.roboswag.components.requests; + +import android.support.annotation.NonNull; + +import com.google.api.client.http.AbstractHttpContent; +import com.squareup.okhttp.MediaType; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.RequestBody; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * Created by Gavriil Sitnikov on 07/14. + * Post request that returns data in JSON format + */ +public abstract class AbstractPostJsonRequest extends AbstractJsonRequest { + + @NonNull + protected abstract AbstractHttpContent getContent(); + + protected AbstractPostJsonRequest(@NonNull final Class responseResultType) { + super(responseResultType); + } + + @NonNull + @Override + protected Request.Builder createHttpRequest() throws IOException { + final AbstractHttpContent content = getContent(); + final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + getContent().writeTo(byteArrayOutputStream); + return super.createHttpRequest().post(RequestBody.create( + MediaType.parse(content.getMediaType().build()), byteArrayOutputStream.toByteArray())); + } + +} diff --git a/src/main/java/org/roboswag/components/utils/UiUtils.java b/src/main/java/org/roboswag/components/utils/UiUtils.java new file mode 100644 index 0000000..e5418df --- /dev/null +++ b/src/main/java/org/roboswag/components/utils/UiUtils.java @@ -0,0 +1,20 @@ +package org.roboswag.components.utils; + +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +/** + * Created by Gavriil Sitnikov on 13/11/2015. + * TODO: fill description + */ +public class UiUtils { + + @NonNull + public static View inflate(@LayoutRes int layoutId, @NonNull ViewGroup parent) { + return LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false); + } + +}