diff --git a/app/build.gradle b/app/build.gradle index 264ce83..6defda2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -25,6 +25,8 @@ android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 + + coreLibraryDesugaringEnabled true } } @@ -49,5 +51,8 @@ dependencies { implementation 'com.journeyapps:zxing-android-embedded:4.1.0' implementation 'com.squareup.okhttp3:okhttp:4.9.3' implementation 'com.github.MikeOrtiz:TouchImageView:3.6' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.0.1' + implementation 'com.squareup.retrofit2:converter-jackson:2.9.0' + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3' } } \ No newline at end of file diff --git a/app/release/app-release.apk b/app/release/app-release.apk new file mode 100644 index 0000000..05d8b47 Binary files /dev/null and b/app/release/app-release.apk differ diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json new file mode 100644 index 0000000..e6897ad --- /dev/null +++ b/app/release/output-metadata.json @@ -0,0 +1,20 @@ +{ + "version": 3, + "artifactType": { + "type": "APK", + "kind": "Directory" + }, + "applicationId": "com.utopiaindustries.qualitychecker", + "variantName": "release", + "elements": [ + { + "type": "SINGLE", + "filters": [], + "attributes": [], + "versionCode": 1, + "versionName": "1.0", + "outputFile": "app-release.apk" + } + ], + "elementType": "File" +} \ No newline at end of file diff --git a/app/src/main/java/com/utopiaindustries/qualitychecker/apiservice/GiteaClient.java b/app/src/main/java/com/utopiaindustries/qualitychecker/apiservice/GiteaClient.java new file mode 100644 index 0000000..88e6829 --- /dev/null +++ b/app/src/main/java/com/utopiaindustries/qualitychecker/apiservice/GiteaClient.java @@ -0,0 +1,28 @@ +package com.utopiaindustries.qualitychecker.apiservice; + +import okhttp3.OkHttpClient; +import retrofit2.Retrofit; +import retrofit2.converter.jackson.JacksonConverterFactory; + +public class GiteaClient { + private static Retrofit retrofit; + private static final String BASE_URL = "https://git.utopiadeals.com/api/v1/repos/UIND/Quality-Checker-Android-Releases/"; + + /** + * get retrofit instance + */ + public static Retrofit getInstance() { + if ( retrofit == null ) { + try { + retrofit = new Retrofit.Builder() + .baseUrl( BASE_URL ) + .addConverterFactory( JacksonConverterFactory.create() ) + .client( SSLCheckHttpClient.getOkHttpClient() ) + .build(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + return retrofit; + } +} diff --git a/app/src/main/java/com/utopiaindustries/qualitychecker/apiservice/GiteaRestService.java b/app/src/main/java/com/utopiaindustries/qualitychecker/apiservice/GiteaRestService.java new file mode 100644 index 0000000..74e3258 --- /dev/null +++ b/app/src/main/java/com/utopiaindustries/qualitychecker/apiservice/GiteaRestService.java @@ -0,0 +1,16 @@ +package com.utopiaindustries.qualitychecker.apiservice; + +import com.utopiaindustries.qualitychecker.utils.Release; + +import retrofit2.Call; +import retrofit2.http.GET; +import retrofit2.http.Query; + +public interface GiteaRestService { + + /** + * get latest release + */ + @GET( "releases/latest" ) + Call getLatestRelease(@Query( "access_token" ) String accessToken ); +} diff --git a/app/src/main/java/com/utopiaindustries/qualitychecker/apiservice/RetrofitClient.java b/app/src/main/java/com/utopiaindustries/qualitychecker/apiservice/RetrofitClient.java index 28e238d..70a96f8 100644 --- a/app/src/main/java/com/utopiaindustries/qualitychecker/apiservice/RetrofitClient.java +++ b/app/src/main/java/com/utopiaindustries/qualitychecker/apiservice/RetrofitClient.java @@ -19,8 +19,8 @@ import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; public class RetrofitClient { - //private final static String BASE_URL = "https://portal.utopiaindustries.pk/uind/"; - private final static String BASE_URL = "http://192.168.91.44:8081/uind/";//"http://192.168.91.44:8081/uind/";//"http://192.168.90.27:8080/uind/";//"http://192.168.91.16:8080/uind/"; + private final static String BASE_URL = "https://portal.utopiaindustries.pk/uind/"; + //private final static String BASE_URL = "http://192.168.91.44:8081/uind/";//"http://192.168.91.44:8081/uind/";//"http://192.168.90.27:8080/uind/";//"http://192.168.91.16:8080/uind/"; private static Retrofit retrofit; diff --git a/app/src/main/java/com/utopiaindustries/qualitychecker/ui/activities/HomeActivity.java b/app/src/main/java/com/utopiaindustries/qualitychecker/ui/activities/HomeActivity.java index 3ba59ef..a5a3bf9 100644 --- a/app/src/main/java/com/utopiaindustries/qualitychecker/ui/activities/HomeActivity.java +++ b/app/src/main/java/com/utopiaindustries/qualitychecker/ui/activities/HomeActivity.java @@ -6,13 +6,17 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; +import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.ImageView; +import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; @@ -30,6 +34,8 @@ import com.google.android.material.tabs.TabLayout; import com.utopiaindustries.qualitychecker.R; import com.utopiaindustries.qualitychecker.apiservice.ApiService; import com.utopiaindustries.qualitychecker.apiservice.ApiServiceFactory; +import com.utopiaindustries.qualitychecker.apiservice.GiteaClient; +import com.utopiaindustries.qualitychecker.apiservice.GiteaRestService; import com.utopiaindustries.qualitychecker.db.CheckpointRepository; import com.utopiaindustries.qualitychecker.db.DefectRepository; import com.utopiaindustries.qualitychecker.db.DimensionRepository; @@ -53,9 +59,13 @@ import com.utopiaindustries.qualitychecker.ui.activities.fragments.ReportsFragme import com.utopiaindustries.qualitychecker.ui.adapter.PagerAdapter; import com.utopiaindustries.qualitychecker.ui.adapter.ReportAdapter; import com.utopiaindustries.qualitychecker.ui.fragments.FirstStepFragment; +import com.utopiaindustries.qualitychecker.utils.FileUtils; +import com.utopiaindustries.qualitychecker.utils.PropertyReader; +import com.utopiaindustries.qualitychecker.utils.Release; import java.util.List; import java.util.Objects; +import java.util.Properties; import retrofit2.Call; import retrofit2.Callback; @@ -63,7 +73,7 @@ import retrofit2.Response; public class HomeActivity extends AppCompatActivity implements View.OnClickListener { - private Button createReportBtn,refreshReportsBtn,logoutBtn,fetchProductBtn; + private Button createReportBtn,refreshReportsBtn,logoutBtn,fetchProductBtn, appUpdateBtn; //private RecyclerView recyclerView; private ApiService apiService; private TextView usernameTitle;//, emptyReportTextView; @@ -72,11 +82,13 @@ public class HomeActivity extends AppCompatActivity implements View.OnClickListe private InspectionReportService inspectionReportService; private NetworkReceiver networkReceiver; private boolean isReceiverRegistered = false; + private ProgressBar progressBar; TabLayout tabLayout; ViewPager viewPager; PagerAdapter pagerAdapter; + private String currentVersionName; @SuppressLint("SourceLockedOrientationActivity") @Override @@ -102,6 +114,8 @@ public class HomeActivity extends AppCompatActivity implements View.OnClickListe refreshReportsBtn = findViewById( R.id.refresh_btn ); logoutBtn = findViewById( R.id.logout_btn ); fetchProductBtn = findViewById( R.id.fetch_product_btn ); + appUpdateBtn = findViewById(R.id.app_update_btn); + progressBar = findViewById(R.id.progressBar); //recyclerView = findViewById( R.id.reports_recyclerview ); usernameTitle = findViewById( R.id.username_title ); profileImage = findViewById( R.id.profile_image ); @@ -123,6 +137,7 @@ public class HomeActivity extends AppCompatActivity implements View.OnClickListe createReportBtn.setOnClickListener( this ); logoutBtn.setOnClickListener( this ); fetchProductBtn.setOnClickListener( this ); + appUpdateBtn.setOnClickListener( this ); //recyclerView.setLayoutManager( new LinearLayoutManager( this ) ); @@ -202,8 +217,23 @@ public class HomeActivity extends AppCompatActivity implements View.OnClickListe Toast.makeText( this, "network not available", Toast.LENGTH_LONG ).show(); } } + + if ( id == R.id.app_update_btn) { + + if (!FileUtils.isNetworkConnected(this)) { + Toast.makeText(this, "No Internet Connection", Toast.LENGTH_LONG).show(); + } + else { + checkForUpdates(); + } + + } } +private int generateRandomNumber(int min, int max) { + return (int) (Math.random() * ((max - min) + 1)) + min; +} + private void updateProfileImage(){ SharedPreferences sharedPreferences = getSharedPreferences("login_prefs", Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); @@ -220,7 +250,7 @@ public class HomeActivity extends AppCompatActivity implements View.OnClickListe editor.apply(); usernameTitle.setText( response.body().getName() ); store.setEmployeePhoto( response.body() ); - Log.e("Profile-Image: ",""+store.getProfileImage()); + //Log.e("Profile-Image: ",""+store.getProfileImage()); Glide.with( getBaseContext() ) .load( store.getProfileImage( ) ) .into( profileImage ); @@ -466,4 +496,63 @@ public class HomeActivity extends AppCompatActivity implements View.OnClickListe isReceiverRegistered = false; // Mark the receiver as unregistered } } + + /** + * check for updates + */ + private void checkForUpdates() { + Log.e("checkForUpdates: ","*****"); + PackageManager packageManager = getPackageManager(); + try { + PackageInfo info = packageManager.getPackageInfo( getPackageName(), 0 ); + currentVersionName = info.versionName; + Log.e("currentVersionName: ",""+currentVersionName); + + } catch ( Exception e ) { + Log.e("Version-Exception: ",""+e.getMessage()); + e.printStackTrace(); + } + // adjust views + progressBar.setVisibility( View.VISIBLE ); + // get properties + Properties properties = PropertyReader.getProperties( HomeActivity.this ); + String token = properties.getProperty( "gitea_access_token" ); + // send request + GiteaRestService restService = GiteaClient.getInstance().create( GiteaRestService.class ); + Call call = restService.getLatestRelease( token ); + call.enqueue( new Callback() { + @Override + public void onResponse( Call call, Response response ) { + Log.e("Response: ",""+response.body()); + if ( response.body() != null ) { + Release release = response.body(); + try { + float releaseVersion = Float.parseFloat( release.getName().replace( "v", "" ) ); + float currentVersion = Float.parseFloat( currentVersionName.replace( "v", "" ) ); + if ( releaseVersion > currentVersion && !FileUtils.isNullOrEmpty( release.getDownloadUrl() ) ) { + String msg = String.format( "Updating to version %s", release.getName() ); + Toast.makeText( HomeActivity.this, msg, Toast.LENGTH_LONG ).show(); + Intent intent = new Intent( Intent.ACTION_VIEW, Uri.parse( release.getDownloadUrl() ) ); + startActivity( intent ); + //startApkDownloadAndPerformUpdate( release.getDownloadUrl(), release.getName() ); + } else { + Toast.makeText( HomeActivity.this, "Latest version is already installed", Toast.LENGTH_LONG ).show(); + } + } catch ( Exception e ) { + Log.e("Response-Exception: ",""+e.getMessage()); + Toast.makeText( HomeActivity.this, e.getMessage(), Toast.LENGTH_LONG ).show(); + e.printStackTrace(); + } + } + progressBar.setVisibility( View.INVISIBLE ); + } + + @Override + public void onFailure( Call call, Throwable t ) { + progressBar.setVisibility( View.INVISIBLE ); + Log.e("Failure: ",""+t.getMessage()); + t.printStackTrace(); + } + } ); + } } \ No newline at end of file diff --git a/app/src/main/java/com/utopiaindustries/qualitychecker/ui/activities/LoginActivity.java b/app/src/main/java/com/utopiaindustries/qualitychecker/ui/activities/LoginActivity.java index c4673b5..8f0e6ae 100644 --- a/app/src/main/java/com/utopiaindustries/qualitychecker/ui/activities/LoginActivity.java +++ b/app/src/main/java/com/utopiaindustries/qualitychecker/ui/activities/LoginActivity.java @@ -5,6 +5,8 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Bundle; @@ -12,6 +14,7 @@ import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.ProgressBar; +import android.widget.TextView; import android.widget.Toast; import androidx.activity.EdgeToEdge; @@ -37,6 +40,7 @@ public class LoginActivity extends AppCompatActivity { private ProgressBar progressBar; private Button loginButton; private InspectionReportService reportService; + TextView txtVersion; @SuppressLint("SourceLockedOrientationActivity") @Override @@ -60,10 +64,13 @@ public class LoginActivity extends AppCompatActivity { password = findViewById( R.id.password ); loginButton = findViewById( R.id.login_btn ); progressBar = findViewById( R.id.progressBar ); + txtVersion = findViewById(R.id.txt_version); SharedPreferences sharedPreferences = getSharedPreferences("login_prefs", Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); + setAppVersion(); + loginButton.setOnClickListener(v -> { try { progressBar.setVisibility( View.VISIBLE ); @@ -106,6 +113,17 @@ public class LoginActivity extends AppCompatActivity { }); } + public void setAppVersion() { + PackageManager packageManager = getPackageManager(); + try { + PackageInfo info = packageManager.getPackageInfo( getPackageName(), 0 ); + txtVersion.setText(String.format("Version: %s", info.versionName)); + + } catch ( Exception e ) { + e.printStackTrace(); + } + } + private void isUserAlreadyLoginAndAuthorize() { SharedPreferences sharedPreferences = getSharedPreferences("login_prefs", Context.MODE_PRIVATE); diff --git a/app/src/main/java/com/utopiaindustries/qualitychecker/utils/DateTimeUtils.java b/app/src/main/java/com/utopiaindustries/qualitychecker/utils/DateTimeUtils.java new file mode 100644 index 0000000..d4a0506 --- /dev/null +++ b/app/src/main/java/com/utopiaindustries/qualitychecker/utils/DateTimeUtils.java @@ -0,0 +1,22 @@ +package com.utopiaindustries.qualitychecker.utils; + +import android.os.Build; + +import androidx.annotation.RequiresApi; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class DateTimeUtils { + + public static final String HTML5_DATETIME_INPUT_FORMAT_WITH_SECONDS = "yyyy-MM-dd'T'HH:mm:ss"; + + /** + * format localdatetime into a given format string + */ + @RequiresApi(api = Build.VERSION_CODES.O) + public static String getFormattedDateTimeString(LocalDateTime dateTime, String dateTimeFormat ) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern( dateTimeFormat ); + return dateTime.format( formatter ); + } +} diff --git a/app/src/main/java/com/utopiaindustries/qualitychecker/utils/FileUtils.java b/app/src/main/java/com/utopiaindustries/qualitychecker/utils/FileUtils.java index 5ab36f2..c1fded8 100644 --- a/app/src/main/java/com/utopiaindustries/qualitychecker/utils/FileUtils.java +++ b/app/src/main/java/com/utopiaindustries/qualitychecker/utils/FileUtils.java @@ -4,6 +4,8 @@ import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; import android.net.Uri; import android.os.Handler; import android.os.Looper; @@ -204,4 +206,17 @@ public class FileUtils { } }).start(); } + + /** + * is null or empty + */ + public static boolean isNullOrEmpty( String str ) { + return str == null || str.isEmpty(); + } + + public static boolean isNetworkConnected(Context context) { + ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo(); + return activeNetwork != null && activeNetwork.isConnectedOrConnecting(); + } } diff --git a/app/src/main/java/com/utopiaindustries/qualitychecker/utils/PropertyReader.java b/app/src/main/java/com/utopiaindustries/qualitychecker/utils/PropertyReader.java new file mode 100644 index 0000000..ada8e0f --- /dev/null +++ b/app/src/main/java/com/utopiaindustries/qualitychecker/utils/PropertyReader.java @@ -0,0 +1,25 @@ +package com.utopiaindustries.qualitychecker.utils; + +import android.content.Context; +import android.content.res.Resources; + + +import com.utopiaindustries.qualitychecker.R; + +import java.io.InputStream; +import java.util.Properties; + +public class PropertyReader { + + public static Properties getProperties( Context context ) { + Properties properties = new Properties(); + try { + Resources resources = context.getResources(); + InputStream inputStream = resources.openRawResource( R.raw.application ); + properties.load( inputStream ); + } catch ( Exception e ) { + e.printStackTrace(); + } + return properties; + } +} diff --git a/app/src/main/java/com/utopiaindustries/qualitychecker/utils/Release.java b/app/src/main/java/com/utopiaindustries/qualitychecker/utils/Release.java new file mode 100644 index 0000000..d6465be --- /dev/null +++ b/app/src/main/java/com/utopiaindustries/qualitychecker/utils/Release.java @@ -0,0 +1,68 @@ +package com.utopiaindustries.qualitychecker.utils; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.fasterxml.jackson.databind.annotation.JsonNaming; + +import java.util.List; + +@JsonIgnoreProperties( ignoreUnknown = true ) +@JsonNaming( PropertyNamingStrategy.SnakeCaseStrategy.class ) +public class Release { + private String id; + private String tagName; + private String name; + private List assets; + + public Release() { + } + + public String getId() { + return id; + } + + public void setId( String id ) { + this.id = id; + } + + public String getTagName() { + return tagName; + } + + public void setTagName( String tagName ) { + this.tagName = tagName; + } + + public String getName() { + return name; + } + + public void setName( String name ) { + this.name = name; + } + + public List getAssets() { + return assets; + } + + public void setAssets( List assets ) { + this.assets = assets; + } + + public String getDownloadUrl() { + if ( this.assets == null || this.assets.isEmpty() ) { + return null; + } + return this.assets.get( 0 ).getBrowserDownloadUrl(); + } + + @Override + public String toString() { + return "Release{" + + "id='" + id + '\'' + + ", tagName='" + tagName + '\'' + + ", name='" + name + '\'' + + ", assets=" + assets + + '}'; + } +} diff --git a/app/src/main/java/com/utopiaindustries/qualitychecker/utils/ReleaseAsset.java b/app/src/main/java/com/utopiaindustries/qualitychecker/utils/ReleaseAsset.java new file mode 100644 index 0000000..edd9a34 --- /dev/null +++ b/app/src/main/java/com/utopiaindustries/qualitychecker/utils/ReleaseAsset.java @@ -0,0 +1,95 @@ +package com.utopiaindustries.qualitychecker.utils; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import com.utopiaindustries.qualitychecker.utils.jackson.ZonedDateTimeDeserializer; + +import java.time.ZonedDateTime; + + +@JsonIgnoreProperties( ignoreUnknown = true ) +@JsonNaming( PropertyNamingStrategy.SnakeCaseStrategy.class ) +public class ReleaseAsset { + private String id; + private String name; + private long size; + private long downloadCount; + @JsonDeserialize( using = ZonedDateTimeDeserializer.class ) + private ZonedDateTime createdAt; + private String uuid; + private String browserDownloadUrl; + + public ReleaseAsset() { + } + + public String getId() { + return id; + } + + public void setId( String id ) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName( String name ) { + this.name = name; + } + + public long getSize() { + return size; + } + + public void setSize( long size ) { + this.size = size; + } + + public long getDownloadCount() { + return downloadCount; + } + + public void setDownloadCount( long downloadCount ) { + this.downloadCount = downloadCount; + } + + public ZonedDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt( ZonedDateTime createdAt ) { + this.createdAt = createdAt; + } + + public String getUuid() { + return uuid; + } + + public void setUuid( String uuid ) { + this.uuid = uuid; + } + + public String getBrowserDownloadUrl() { + return browserDownloadUrl; + } + + public void setBrowserDownloadUrl( String browserDownloadUrl ) { + this.browserDownloadUrl = browserDownloadUrl; + } + + @Override + public String toString() { + return "ReleaseAsset{" + + "id='" + id + '\'' + + ", name='" + name + '\'' + + ", size=" + size + + ", downloadCount=" + downloadCount + + ", createdAt=" + createdAt + + ", uuid='" + uuid + '\'' + + ", browserDownloadUrl='" + browserDownloadUrl + '\'' + + '}'; + } +} diff --git a/app/src/main/java/com/utopiaindustries/qualitychecker/utils/jackson/LocalDateTimeDeserializer.java b/app/src/main/java/com/utopiaindustries/qualitychecker/utils/jackson/LocalDateTimeDeserializer.java new file mode 100644 index 0000000..d969605 --- /dev/null +++ b/app/src/main/java/com/utopiaindustries/qualitychecker/utils/jackson/LocalDateTimeDeserializer.java @@ -0,0 +1,35 @@ +package com.utopiaindustries.qualitychecker.utils.jackson; + +import android.os.Build; + +import androidx.annotation.RequiresApi; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.utopiaindustries.qualitychecker.utils.DateTimeUtils; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class LocalDateTimeDeserializer extends StdDeserializer { + + private static final long serialVersionUID = 1L; + + @RequiresApi(api = Build.VERSION_CODES.O) + public LocalDateTimeDeserializer() { + super( LocalDateTime.class ); + } + + @RequiresApi(api = Build.VERSION_CODES.O) + @Override + public LocalDateTime deserialize( JsonParser parser, DeserializationContext ctxt ) throws IOException, JsonProcessingException { + JsonNode node = parser.getCodec().readTree( parser ); + String dateStr = node.asText(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern( DateTimeUtils.HTML5_DATETIME_INPUT_FORMAT_WITH_SECONDS ); + return LocalDateTime.parse( dateStr, formatter ); + } +} diff --git a/app/src/main/java/com/utopiaindustries/qualitychecker/utils/jackson/LocalDateTimeSerializer.java b/app/src/main/java/com/utopiaindustries/qualitychecker/utils/jackson/LocalDateTimeSerializer.java new file mode 100644 index 0000000..ced6fbe --- /dev/null +++ b/app/src/main/java/com/utopiaindustries/qualitychecker/utils/jackson/LocalDateTimeSerializer.java @@ -0,0 +1,25 @@ +package com.utopiaindustries.qualitychecker.utils.jackson; + + +import android.os.Build; + +import androidx.annotation.RequiresApi; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.utopiaindustries.qualitychecker.utils.DateTimeUtils; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +@RequiresApi(api = Build.VERSION_CODES.O) +public class LocalDateTimeSerializer extends JsonSerializer { + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern( DateTimeUtils.HTML5_DATETIME_INPUT_FORMAT_WITH_SECONDS ); + + @Override + public void serialize( LocalDateTime value, JsonGenerator gen, SerializerProvider serializers ) throws IOException { + gen.writeString( value.format( FORMATTER ) ); + } +} diff --git a/app/src/main/java/com/utopiaindustries/qualitychecker/utils/jackson/ZonedDateTimeDeserializer.java b/app/src/main/java/com/utopiaindustries/qualitychecker/utils/jackson/ZonedDateTimeDeserializer.java new file mode 100644 index 0000000..d4a5093 --- /dev/null +++ b/app/src/main/java/com/utopiaindustries/qualitychecker/utils/jackson/ZonedDateTimeDeserializer.java @@ -0,0 +1,35 @@ +package com.utopiaindustries.qualitychecker.utils.jackson; + +import android.os.Build; + +import androidx.annotation.RequiresApi; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; + +public class ZonedDateTimeDeserializer extends StdDeserializer { + + private static final long serialVersionUID = 1L; + + @RequiresApi(api = Build.VERSION_CODES.O) + public ZonedDateTimeDeserializer() { + super( LocalDateTime.class ); + } + + @RequiresApi(api = Build.VERSION_CODES.O) + @Override + public ZonedDateTime deserialize( JsonParser parser, DeserializationContext ctxt ) throws IOException, JsonProcessingException { + JsonNode node = parser.getCodec().readTree( parser ); + String dateStr = node.asText(); + DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME; + return ZonedDateTime.parse( dateStr, formatter ); + } +} diff --git a/app/src/main/res/layout/activity_home.xml b/app/src/main/res/layout/activity_home.xml index 6922529..2305fc7 100644 --- a/app/src/main/res/layout/activity_home.xml +++ b/app/src/main/res/layout/activity_home.xml @@ -169,5 +169,25 @@ android:layout_toStartOf="@id/logout_btn" android:text="Fetch" /> +