Add version

Add check for new update
master
saad.siddiq 2025-06-03 17:56:30 +05:00
parent d5f0f38566
commit ee78008de1
15 changed files with 440 additions and 1 deletions

View File

@ -45,5 +45,8 @@ dependencies {
implementation libs.preference
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'
}

View File

@ -1,9 +1,16 @@
package com.utopiaindustries.hseobservationsapp.activities;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
@ -16,17 +23,30 @@ import androidx.lifecycle.ViewModelProvider;
import com.utopiaindustries.hseobservationsapp.R;
import com.utopiaindustries.hseobservationsapp.apiservice.ApiService;
import com.utopiaindustries.hseobservationsapp.apiservice.ApiServiceFactory;
import com.utopiaindustries.hseobservationsapp.apiservice.GiteaClient;
import com.utopiaindustries.hseobservationsapp.apiservice.GiteaRestService;
import com.utopiaindustries.hseobservationsapp.helper.Helper;
import com.utopiaindustries.hseobservationsapp.helper.Preference;
import com.utopiaindustries.hseobservationsapp.helper.PropertyReader;
import com.utopiaindustries.hseobservationsapp.helper.Release;
import com.utopiaindustries.hseobservationsapp.utils.ProgressDialogFragment;
import com.utopiaindustries.hseobservationsapp.viewmodels.LoginViewModel;
import java.util.Properties;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class LoginActivity extends AppCompatActivity {
EditText tfEmail, tfPassword;
Button btnLogin;
LoginViewModel loginViewModel;
ApiService apiService;
TextView txtVersion;
ImageView imgCheckUpdate;
private String currentVersionName;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -60,12 +80,34 @@ public class LoginActivity extends AppCompatActivity {
finish();*/
}
});
imgCheckUpdate.setOnClickListener(v -> {
if (!Helper.isNetworkConnected(this)) {
Toast.makeText(this, "No Internet Connection", Toast.LENGTH_LONG).show();
}
else {
checkForUpdates();
}
});
}
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();
}
}
public void initializeLayout() {
tfEmail = findViewById(R.id.tf_email);
tfPassword = findViewById(R.id.tf_password);
btnLogin = findViewById(R.id.btn_login);
txtVersion = findViewById(R.id.txt_version);
imgCheckUpdate = findViewById(R.id.img_check_update);
apiService = ApiServiceFactory.getApiService();
loginViewModel = new ViewModelProvider(this).get(LoginViewModel.class);
@ -102,6 +144,8 @@ public class LoginActivity extends AppCompatActivity {
}
});
setAppVersion();
/*loginViewModel.getUserLiveData().observe(this, user -> {
if (user != null) {
Preference.setMyBooleanPref(Helper.project_file, "isLoggedIn", getApplicationContext(), true);
@ -156,4 +200,63 @@ public class LoginActivity extends AppCompatActivity {
progressDialog.dismiss();
}
}
/**
* 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
showProgressDialog();
// get properties
Properties properties = PropertyReader.getProperties( LoginActivity.this );
String token = properties.getProperty( "gitea_access_token" );
// send request
GiteaRestService restService = GiteaClient.getInstance().create( GiteaRestService.class );
Call<Release> call = restService.getLatestRelease( token );
call.enqueue( new Callback<Release>() {
@Override
public void onResponse( Call<Release> call, Response<Release> 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 && !Helper.isNullOrEmpty( release.getDownloadUrl() ) ) {
String msg = String.format( "Updating to version %s", release.getName() );
Toast.makeText( LoginActivity.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( LoginActivity.this, "Latest version is already installed", Toast.LENGTH_LONG ).show();
}
} catch ( Exception e ) {
Log.e("Response-Exception: ",""+e.getMessage());
Toast.makeText( LoginActivity.this, e.getMessage(), Toast.LENGTH_LONG ).show();
e.printStackTrace();
}
}
dismissProgressDialog();
}
@Override
public void onFailure( Call<Release> call, Throwable t ) {
dismissProgressDialog();
Log.e("Failure: ",""+t.getMessage());
t.printStackTrace();
}
} );
}
}

View File

@ -1,6 +1,8 @@
package com.utopiaindustries.hseobservationsapp.activities;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;
@ -33,7 +35,7 @@ public class SplashActivity extends AppCompatActivity {
});
txtVersion = findViewById(R.id.txt_version);
txtVersion.setText(getResources().getString(R.string.app_version));
setAppVersion();
isLoggedIn = Preference.getMyBooleanPref(Helper.project_file, "isLoggedIn", getApplicationContext());
@ -54,4 +56,15 @@ public class SplashActivity extends AppCompatActivity {
}
}, TIMER);
}
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();
}
}
}

View File

@ -0,0 +1,27 @@
package com.utopiaindustries.hseobservationsapp.apiservice;
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;
}
}

View File

@ -0,0 +1,16 @@
package com.utopiaindustries.hseobservationsapp.apiservice;
import com.utopiaindustries.hseobservationsapp.helper.Release;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface GiteaRestService {
/**
* get latest release
*/
@GET( "releases/latest" )
Call<Release> getLatestRelease(@Query( "access_token" ) String accessToken );
}

View File

@ -0,0 +1,52 @@
package com.utopiaindustries.hseobservationsapp.apiservice;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.OkHttpClient;
public class SSLCheckHttpClient {
public static OkHttpClient getOkHttpClient() throws NoSuchAlgorithmException, KeyManagementException {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
return new OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0])
.hostnameVerifier((hostname, session) -> true)
.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.build();
}
}

View File

@ -187,4 +187,8 @@ public class Helper {
}
}
public static boolean isNullOrEmpty( String str ) {
return str == null || str.isEmpty();
}
}

View File

@ -0,0 +1,24 @@
package com.utopiaindustries.hseobservationsapp.helper;
import android.content.Context;
import android.content.res.Resources;
import com.utopiaindustries.hseobservationsapp.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;
}
}

View File

@ -0,0 +1,69 @@
package com.utopiaindustries.hseobservationsapp.helper;
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<ReleaseAsset> 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<ReleaseAsset> getAssets() {
return assets;
}
public void setAssets( List<ReleaseAsset> 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 +
'}';
}
}

View File

@ -0,0 +1,89 @@
package com.utopiaindustries.hseobservationsapp.helper;
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 + '\'' +
'}';
}
}

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="35dp"
android:height="35dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:pathData="M9.405,1.05c-0.413,-1.4 -2.397,-1.4 -2.81,0l-0.1,0.34a1.464,1.464 0,0 1,-2.105 0.872l-0.31,-0.17c-1.283,-0.698 -2.686,0.705 -1.987,1.987l0.169,0.311c0.446,0.82 0.023,1.841 -0.872,2.105l-0.34,0.1c-1.4,0.413 -1.4,2.397 0,2.81l0.34,0.1a1.464,1.464 0,0 1,0.872 2.105l-0.17,0.31c-0.698,1.283 0.705,2.686 1.987,1.987l0.311,-0.169a1.464,1.464 0,0 1,2.105 0.872l0.1,0.34c0.413,1.4 2.397,1.4 2.81,0l0.1,-0.34a1.464,1.464 0,0 1,2.105 -0.872l0.31,0.17c1.283,0.698 2.686,-0.705 1.987,-1.987l-0.169,-0.311a1.464,1.464 0,0 1,0.872 -2.105l0.34,-0.1c1.4,-0.413 1.4,-2.397 0,-2.81l-0.34,-0.1a1.464,1.464 0,0 1,-0.872 -2.105l0.17,-0.31c0.698,-1.283 -0.705,-2.686 -1.987,-1.987l-0.311,0.169a1.464,1.464 0,0 1,-2.105 -0.872l-0.1,-0.34zM8,10.93a2.929,2.929 0,1 1,0 -5.86,2.929 2.929,0 0,1 0,5.858z"
android:fillColor="@color/slate700"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#5B5858" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M21,10.12h-6.78l2.74,-2.82c-2.73,-2.7 -7.15,-2.8 -9.88,-0.1c-2.73,2.71 -2.73,7.08 0,9.79s7.15,2.71 9.88,0C18.32,15.65 19,14.08 19,12.1h2c0,1.98 -0.88,4.55 -2.64,6.29c-3.51,3.48 -9.21,3.48 -12.72,0c-3.5,-3.47 -3.53,-9.11 -0.02,-12.58s9.14,-3.47 12.65,0L21,3V10.12zM12.5,8v4.25l3.5,2.08l-0.72,1.21L11,13V8H12.5z"/>
</vector>

View File

@ -88,4 +88,26 @@
android:textSize="@dimen/_15sdp" />
</LinearLayout>
<TextView
android:id="@+id/txt_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginBottom="28dp"
android:textStyle="bold"
android:text="V-1.0"
android:textSize="@dimen/_13sdp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<ImageView
android:id="@+id/img_check_update"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/icon_update" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1 @@
gitea_access_token=3efaddad018362af36b515c091d66da34b97abe2

View File

@ -20,6 +20,8 @@
<color name="blue13">#C5EAF8</color>
<color name="blue14">#E2F4FB</color>
<color name="slate700">#334155</color>
<color name="purple01">#9933CC</color>
<color name="purple02">#A041D0</color>
<color name="purple03">#A750D3</color>