Tuesday 7 December 2021

Replace Multi-Launguage String(IOS)

 import org.json.JSONArray

import java.io.*


fun main() {

var match = 0
var not = 0

val englishLangData = readJson1()
val otherLangData = readJson3()
val list = englishLangData.split(";")
// Main Local.strings
for (item in list) {
try {
val key1 = item.trim().split("=")[1].replace("\"", "").toString().trim()
val value1 = item.trim().split("=")[1].replace("\"", "").toString().trim()

// CODE- language to be replaced
val jsonArr = JSONArray(otherLangData)
for (item2 in jsonArr) {
val s = item2.toString()
val j1 = JSONArray(s)
val s1 = j1[0].toString().trim()
val s2 = j1[1].toString().trim()
if (s1.equals(value1, true)) {

val s = "\""+key1+"\" = \""+s2+"\";"
val s2 = "\n" + s
val fileWriter = FileWriter("C:\\Projects\\Project\\Localizable.strings", true)
fileWriter.write(s2)
fileWriter.close()
match = match + 1
break
}
}
} catch (exc: Exception) {
}
}


println("matched size : " + match)
println("not matched size : " + not)

}


fun readJson1(): String {

val writer: Writer = StringWriter()
val buffer = CharArray(1024)

try {
val file1 = File("C:\\Projects\\Project\\EicherLiveStaticStrings_Malyalam.xlsx")
val file = File("C:\\Projects\\Project\\Localizable_main_formatted.strings")
val reader: Reader = BufferedReader(FileReader(file))
var n1: Int = 0
while (reader.read(buffer).also({ n1 = it }) != -1) {
writer.write(buffer, 0, n1)
}
} finally {
// fil.close()
}

val jsonString: String = writer.toString()
return jsonString
}


fun readJson3(): String {

val writer: Writer = StringWriter()
val buffer = CharArray(1024)

try {
val file = File("C:\\Projects\\Project\\formatted_malayalam_arr_json.json")
val reader: Reader = BufferedReader(FileReader(file))
var n1: Int = 0
while (reader.read(buffer).also({ n1 = it }) != -1) {
writer.write(buffer, 0, n1)
}
} finally {
// fil.close()
}

val jsonString: String = writer.toString()
return jsonString
}

Monday 4 October 2021

Injecting CSS into Webview

XML
==========================================================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
tools:context=".MainActivity"
android:orientation="vertical"
>

<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>

</LinearLayout>
==========================================================


JAVA
===========================================================

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import android.content.DialogInterface;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class WebActivity2 extends AppCompatActivity {

WebView webView;

private String style;
private final static String CREATE_CUSTOM_SHEET =
"if (typeof(document.head) != 'undefined' && typeof(customSheet) == 'undefined') {"
+ "var customSheet = (function() {"
+ "var style = document.createElement(\"style\");"
+ "style.appendChild(document.createTextNode(\"\"));"
+ "document.head.appendChild(style);"
+ "return style.sheet;"
+ "})();"
+ "}";
DisplayMetrics displayMetrics = new DisplayMetrics();


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_web2);

// setTitle("360 degree View Test");
webView = (WebView) findViewById(R.id.webView);

getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int height = displayMetrics.heightPixels;
style= "#wr360PlayerId {"+
"width: 100%;"+
"height: 100% !important;"+
"}";

showWebPage();
}



private void showWebPage(){
String sURL = "https://www.eichertrucksandbuses.com/360/PRO-6042/exterior/PRO-6042.html";
webView.setWebViewClient(new MyWebViewClient());
webView.getSettings().setSupportZoom(true);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setBuiltInZoomControls(true);
webView.getSettings().setUseWideViewPort(true);
webView.getSettings().setLoadWithOverviewMode(true);

webView.loadUrl(sURL);
}

private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}

@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
injectCssIntoWebView(view, style);
}

@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
new WebActivity2().showDialog("Oops", "Something went wrong");
}

}

private void showDialog(String title, String msg){
webView.setVisibility(View.INVISIBLE);
new AlertDialog.Builder(WebActivity2.this)
.setTitle(title)
.setMessage(msg)
.setCancelable(false)
.setIcon(android.R.drawable.ic_dialog_alert)
.setNegativeButton("Retry", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
webView.setVisibility(View.VISIBLE);
showWebPage();
}
})
.setPositiveButton("Back", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
onBackPressed();
}
})
.show();
}


private void injectCssIntoWebView(WebView webView, String... cssRules) {
StringBuilder jsUrl = new StringBuilder("javascript:");
jsUrl
.append(CREATE_CUSTOM_SHEET)
.append("if (typeof(customSheet) != 'undefined') {");
int cnt = 0;
for (String cssRule : cssRules) {
jsUrl
.append("customSheet.insertRule('")
.append(cssRule)
.append("', ")
.append(cnt++)
.append(");");
}
jsUrl.append("}");
System.out.println("### JS: "+jsUrl.toString());
webView.loadUrl(jsUrl.toString());
}


}
===========================================================

AndroidManifest.xml
===========================================================
<activity android:name=".WebActivity2"
android:screenOrientation="landscape"
android:theme="@style/Theme.AppCompat.NoActionBar"
/>
===========================================================


22

Thursday 20 February 2020

BroadCast Receiver


Broadcast Receiver - To listen the system as well as custom intent.

Android OS is firing multiple intents like - SYSTEM_REBOOT, BATTERY_LOW/HIGH,  NETWORK STATUS and so on.

Intent - It is a messaging object which is used to pass the message from one component to another.

1. Create BroadcastReceiver Class

public class BReceiver  extends BroadcastReceiver

2. Register and Filter Intent - Register Broadcast Receiver class to listen to System intent.
and by using IntentFilter we specify which intent app listens.

2.1 Register receiver  in Android Manifest

<receiver android:name=".BReceiver">
    <intent-filter>
        <action android:name="divakar"></action>
    </intent-filter>
</receiver>

2.2 Register receiver programmatically.

final BReceiver bReceiver = new BReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("divakar");
registerReceiver(bReceiver, filter);

if you want to send broadcast localy(within app)

LocalBroadcastManager.getInstance(this).registerReceiver(bReceiver, filter);

3. Receive data
    @Override    public void onReceive(Context context, Intent intent) {

        if (intent.getAction() == Manifest.permission.CHANGE_WIFI_STATE) {
            
        }
    }

4. Send Custom Intent

Intent i = new Intent();
i.setAction("divakar");
i.putExtra("key", "divakar-main-data");
sendBroadcast(i, Manifest.permission.CHANGE_WIFI_STATE);


5. Receive Custom Intent

    @Override    public void onReceive(Context context, Intent intent) {

        if (intent.getAction().equalsIgnoreCase("divakar")) {
            String s = intent.getExtras().getString("key");
            Toast.makeText(context, "Broadcast Receiver called : "+s, Toast.LENGTH_LONG).show();
        }else {
            Toast.makeText(context, "Something changed", Toast.LENGTH_LONG).show();
        }
    }



Sunday 19 May 2019

MVVM Doc




Using MVVM |Android Jetpack



Model–View–ViewModel (MVVM) is a software architectural pattern which facilitates separation of development UI (Activity or Fragment) from the development of the business logic or back-end logic (the data model).



What is Architectural Pattern

An Architectural Pattern is a general, reusable solution to a commonly occurring problem in software architecture. Architectural patterns are similar to Software Design Patterns but have a broader scope. The architectural patterns address various issues such as computer hardware performance limitations, high availability, and minimization of business risk.
An architectural style defines a family of systems in terms of a pattern of structural organization; a vocabulary of components and connectors, with constraints on how they can be combined.

What is MVVM

MVVM stands for Model View ViewModel and it is an architectural pattern for implementing user interfaces.



Why MVVM over MVP

1. Tight Coupling

For each Activity/Fragment (View) we require a Presenter. This is a hardbound rule.
Presenter holds the reference to the Activity and Activity Holds the reference to a presenter 1:1 relationship.
As the complexity of view increases, so does the maintenance and handling of this relationship.
ViewModels are simples classes that interact with the logic/model layer and just exposes states/data and actually has no idea by whom or how that data will be consumed. Only View(Activity) holds the reference to ViewModel and not vice versa, this solves our tight coupling issue. A single view can hold a reference to multiple ViewModels.
Even for complex views we can actually have different ViewModels within same hierarchy.

2. Testability

ViewModels are more Unit Test friendly and there is no dependency of the View as they just expose the state and it can be independently tested without requiring the need for testing how data will be consumed.

3. Relationship with View




In MVP, the role of a Presenter is to drive the View changes and at the same time provide data for completing those operations whereas MVVM, the ViewModel only provides the data, whereas the View is responsible for consuming them and does not hold the reference to the View .The ViewModelcan also hold logic for processing users input, same as the Presenter .
Inshort ,MVVM gives more separation of concerns, less boilerplate and encourage reactive approach. Additionally, we get officially recommended tools straight from Google, so we can worry less about lifecycle, memory leaks and crashes.
Now let’s talk about MVVM components.

MVVM Components

It consists of three moving parts:
  • Data Model — it abstracts the data source. The ViewModel works with the DataModel to get and save the data. it represents the business objects that encapsulate the data and behavior of the application.
  • ViewModel — it exposes streams of data relevant to the View and provides the data for a specific UI component, such as a fragment or activity, and contains data-handling business logic to communicate with the model.
  • View — the UI that users see and view send and receive the data from the view model



The Repository holds all the business logic of the particular app section in the app.



Implementation

Step 1: Add the Gradle dependencies

  1. To add it to your project, open the project level build.gradle file and add the highlighted line as shown below:



2. Open the build.gradle file for your app or module and add dependencies:



Step 2: Create a Data Source

First of all, you will create a data source for your application if you are using RestAPI you might use Retrofit or Volley for parsing the JSON data and if you are using SQL database you will use Room Database or SQLite.
In our case, we are using Room Database to demonstrate how to set up MVVM.
We have already implemented how Room in our project and if you do not know how to use Room then we have also written an article we project code.
//article link and code

Step 3: Create a Repository

Repository is basically a wrapper class which contains the business logic of our app.



As we are Using Room database we need to have ApplicationContext and we will write all the database operation here so the person who is working on the UI does not have to worry about any database operations.
We have already created the Repository class here:



In this Repository class, we will write all the DAO operations and access them in the UI through ViewModel.

=======================
package com.aeologic.moviemvvmdemo.repository;
import android.app.Application;
import android.arch.lifecycle.LiveData;
import android.os.AsyncTask;
import com.aeologic.moviemvvmdemo.dao.MovieDao;
import com.aeologic.moviemvvmdemo.db.MovieDB;
import com.aeologic.moviemvvmdemo.model.Movie;
import java.util.List;
public class MovieRepository {
private MovieDao movieDao;
private LiveData<List<Movie>> allMovies;
public MovieRepository(Application application) {
MovieDB db = MovieDB.getInstance(application);
movieDao = db.movieDao();
allMovies = movieDao.getAllMovies();
}
public void insertMovie(Movie movie) {
new InsertMovieAsyncTask(movieDao).execute(movie);
}
public void updateMovie(Movie movie) {
new UpdateMovieAsyncTask(movieDao).execute(movie);
}
public void deleteMovie(Movie movie) {
new DeleteMovieAsyncTask(movieDao).execute(movie);
}
public void deleteAllMovies() {
new DeleteAllMovieAsyncTask(movieDao).execute();
}
public LiveData<List<Movie>> getAllMovies() {
return allMovies;
}
private static class InsertMovieAsyncTask extends AsyncTask<Movie, Void, Void> {
private MovieDao movieDao;
private InsertMovieAsyncTask(MovieDao movieDao) {
this.movieDao = movieDao;
}
@Override
protected Void doInBackground(Movie... movies) {
movieDao.insertMovie(movies[0]);
return null;
}
}
private static class UpdateMovieAsyncTask extends AsyncTask<Movie, Void, Void> {
private MovieDao movieDao;
private UpdateMovieAsyncTask(MovieDao movieDao) {
this.movieDao = movieDao;
}
@Override
protected Void doInBackground(Movie... movies) {
movieDao.updateMovie(movies[0]);
return null;
}
}
private static class DeleteMovieAsyncTask extends AsyncTask<Movie, Void, Void> {
private MovieDao movieDao;
private DeleteMovieAsyncTask(MovieDao movieDao) {
this.movieDao = movieDao;
}
@Override
protected Void doInBackground(Movie... movies) {
movieDao.deleteMovie(movies[0]);
return null;
}
}
private static class DeleteAllMovieAsyncTask extends AsyncTask<Void, Void, Void> {
private MovieDao movieDao;
private DeleteAllMovieAsyncTask(MovieDao movieDao) {
this.movieDao = movieDao;
}
@Override
protected Void doInBackground(Void... voids) {
movieDao.deleteAllMovies();
return null;
}
}
}

=======================

If you noticed that we have used LiveData above so
LiveData is an observable data holder class. Unlike a regular observable, LiveData is lifecycle-aware, meaning it respects the lifecycle of other app components, such as activities, fragments, or services. This awareness ensures LiveData only updates app component observers that are in an active lifecycle state.
We also have written an article on Using Room with LiveData

Step 4: Create a ViewModel

Now you will create a ViewModel class.
The ViewModelclass allows data to survive configuration changes such as screen rotations.

Why use ViewModel?

The purpose of the ViewModel is to acquire and keep the information that is necessary for an Activity or a Fragment. The Activity or the Fragment should be able to observe changes in the ViewModel. ViewModels usually expose this information via LiveData or Android Data Binding. You can also use any observability construct from your favorite framework.
To know more about ViewModel and how to use it with RoomDatabase we also have written an article on “Using ViewModel with RoomDatabase”
Now create a ViewModel :



We will access the database from the ViewModel because it has two benefits:
  1. It provides abstraction.
  2. ViewModel can handle the lifecycle configurations.
Let’s see the code that we have already written.

Step 4: Use it in UI (Final Step)




If you see the above code, we have instantiated ViewModel class and pass our ViewModel class.
Now we can access the methods we have written in our ViewModel class in our Activity.
View is accessing the dta from ViewModel class and ViewModel is accessing it from Repository class which has all the database operations.


View <-> ViewModel <-> Model

Now you have got an understanding and working of MVVM.
To know how the complete app works on MVVM we have linked Github repository below.

22