Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
grishka committed Apr 16, 2024
0 parents commit 5051a1b
Showing 67 changed files with 2,575 additions and 0 deletions.
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
*.iml
.gradle
/local.properties
/.idea
.DS_Store
build
/captures
.externalNativeBuild
.cxx
local.properties
*.jks
/fastlane/report.xml
/PokeDex/release
59 changes: 59 additions & 0 deletions PokeDex/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
plugins {
id 'com.android.application'
}

android {
androidResources {
generateLocaleConfig true
}

compileSdk 34
defaultConfig {
applicationId "me.grishka.examples.pokedex"
minSdk 21
targetSdk 34
versionCode 1
versionName "1.0.0"
}

buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug{
debuggable true
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
coreLibraryDesugaringEnabled true
}
lintOptions{
checkReleaseBuilds false
abortOnError false
}
buildFeatures{
buildConfig true
}
dependenciesInfo{
includeInApk false
includeInBundle false
}
namespace 'me.grishka.examples.pokedex'
}

dependencies {
api 'androidx.annotation:annotation:1.3.0'
implementation 'com.squareup.okhttp3:okhttp:3.14.9'
implementation 'me.grishka.litex:recyclerview:1.2.1.1'
implementation 'me.grishka.litex:swiperefreshlayout:1.1.0.1'
implementation 'me.grishka.litex:palette:1.0.0'
implementation 'me.grishka.appkit:appkit:1.2.17'
implementation 'com.google.code.gson:gson:2.10.1'
implementation 'org.parceler:parceler-api:1.1.12'
annotationProcessor 'org.parceler:parceler:1.1.12'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
}
42 changes: 42 additions & 0 deletions PokeDex/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

# Keep all model classes as they're used with gson and their names are shown in errors
-keep public class me.grishka.examples.pokedex.model.**{
*;
}

-dontobfuscate

-keepclassmembers class * {
@com.google.gson.annotations.SerializedName <fields>;
}

-keep interface org.parceler.Parcel
-keep @org.parceler.Parcel class * { *; }
-keep class **$$Parcelable { *; }

-keepattributes LineNumberTable
-keepattributes Signature
-keep class com.google.gson.reflect.TypeToken { *; }
-keep class * extends com.google.gson.reflect.TypeToken
-keep public class * implements java.lang.reflect.Type
21 changes: 21 additions & 0 deletions PokeDex/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET"/>

<application
android:name=".PokeDexApplication"
android:label="@string/app_name"
android:supportsRtl="true"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:theme="@style/Theme.PokeDex">

<activity android:name=".MainActivity" android:exported="true" android:configChanges="screenSize|orientation">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>

</application>
</manifest>
Binary file added PokeDex/src/main/ic_launcher-playstore.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package me.grishka.examples.pokedex;

import android.os.Bundle;

import androidx.annotation.Nullable;
import me.grishka.appkit.FragmentStackActivity;
import me.grishka.examples.pokedex.fragments.PokemonListFragment;

public class MainActivity extends FragmentStackActivity{
@Override
public void onCreate(@Nullable Bundle savedInstanceState){
super.onCreate(savedInstanceState);
if(savedInstanceState==null){
showFragment(new PokemonListFragment());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package me.grishka.examples.pokedex;

import android.annotation.SuppressLint;
import android.app.Application;
import android.content.Context;

import me.grishka.appkit.imageloader.ImageCache;
import me.grishka.appkit.utils.NetworkUtils;
import me.grishka.appkit.utils.V;

public class PokeDexApplication extends Application{
@SuppressLint("StaticFieldLeak")
public static Context context;

@Override
public void onCreate(){
super.onCreate();
context=getApplicationContext();
V.setApplicationContext(context);
ImageCache.Parameters params=new ImageCache.Parameters();
params.diskCacheSize=100*1024*1024;
params.maxMemoryCacheSize=Integer.MAX_VALUE;
ImageCache.setParams(params);
NetworkUtils.setUserAgent("poke.dex/"+BuildConfig.VERSION_NAME);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package me.grishka.examples.pokedex.api;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface AllFieldsAreRequired{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package me.grishka.examples.pokedex.api;

import java.io.IOException;

public class ObjectValidationException extends IOException{
public ObjectValidationException(){
}

public ObjectValidationException(String message){
super(message);
}

public ObjectValidationException(String message, Throwable cause){
super(message, cause);
}

public ObjectValidationException(Throwable cause){
super(cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package me.grishka.examples.pokedex.api;

import android.util.Log;

import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonIOException;
import com.google.gson.JsonSyntaxException;

import java.io.IOException;
import java.io.Reader;
import java.util.concurrent.TimeUnit;

import me.grishka.appkit.utils.WorkerThread;
import me.grishka.examples.pokedex.BuildConfig;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;

public class PokeAPIController{
private static final String TAG="PokeAPIController";

public static final Gson gson=new GsonBuilder()
.disableHtmlEscaping()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.create();
private static WorkerThread thread=new WorkerThread("PokeAPIController");
private static OkHttpClient httpClient=new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.build();
private static final PokeAPIController instance=new PokeAPIController();

static{
thread.start();
}

public static PokeAPIController getInstance(){
return instance;
}

public <T> void submitRequest(PokeAPIRequest<T> req){
thread.postRunnable(()->{
try{
Request hReq=new Request.Builder()
.url(req.url)
.addHeader("User-Agent", "poke.dex/"+BuildConfig.VERSION_NAME)
.build();

Call call=httpClient.newCall(hReq);
req.okhttpCall=call;
call.enqueue(new Callback(){
@Override
public void onFailure(Call call, IOException e){
req.okhttpCall=null;
req.onError(e.getMessage(), -1, e);
}

@Override
public void onResponse(Call call, Response response) throws IOException{
req.okhttpCall=null;
if(req.canceled)
return;
T respObj;
try(ResponseBody body=response.body()){
Reader reader=body.charStream();
try{
if(req.respTypeToken!=null)
respObj=gson.fromJson(reader, req.respTypeToken.getType());
else if(req.respClass!=null)
respObj=gson.fromJson(reader, req.respClass);
else
respObj=null;
}catch(JsonIOException|JsonSyntaxException x){
if(BuildConfig.DEBUG)
Log.w(TAG, response+" error parsing or reading body", x);
req.onError(x.getLocalizedMessage(), response.code(), x);
return;
}

try{
req.validateAndPostprocessResponse(respObj, response);
}catch(IOException x){
if(BuildConfig.DEBUG)
Log.w(TAG, response+" error post-processing or validating response", x);
req.onError(x.getLocalizedMessage(), response.code(), x);
return;
}

if(BuildConfig.DEBUG)
Log.d(TAG, response+" parsed successfully: "+respObj);

req.onSuccess(respObj);
}catch(Exception x){
Log.w(TAG, "onResponse: error processing response", x);
req.onError(x.getMessage(), -1, x);
}
}
});
}catch(Throwable x){
Log.w(TAG, "Request "+req+" failed", x);
req.onError(x.getLocalizedMessage(), 0, x);
}
}, 0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package me.grishka.examples.pokedex.api;

import android.content.Context;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import me.grishka.appkit.api.ErrorResponse;

public class PokeAPIErrorResponse extends ErrorResponse{
public final String error;
public final int httpStatus;
public final Throwable underlyingException;

public PokeAPIErrorResponse(String error, int httpStatus, Throwable underlyingException){
this.error=error;
this.httpStatus=httpStatus;
this.underlyingException=underlyingException;
}

@Override
public void bindErrorView(View view){
TextView text=view.findViewById(me.grishka.appkit.R.id.error_text);
text.setText(error);
}

@Override
public void showToast(Context context){
if(context==null)
return;
Toast.makeText(context, error, Toast.LENGTH_SHORT).show();
}
}
Loading

0 comments on commit 5051a1b

Please sign in to comment.