I have an exchange rate application in flutter, but I want to make the currency format the same as below, how can I do it?
My Code :
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
import '../Utils.dart';
class CurrencyInputFormatter extends TextInputFormatter {
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, TextEditingValue newValue) {
if (newValue.selection.baseOffset == 0) {
print(true);
return newValue;
}
double value = double.parse(newValue.text);
final formatter = NumberFormat("#,##0", "tr-TR");
String newText = formatter.format(value);
print(newText);
return newValue.copyWith(
text: newText,
selection: new TextSelection.collapsed(offset: newText.length));
}
}
I want to do
Intl actually provides you a way to do so.
import 'package:intl/intl.dart';
final moneyText = 1000;
NumberFormat.simpleCurrency().format(moneyText);
If you are already using translation, you should have intl already.
You can achieve this with flutter_masked_text package it can do exactly the same.
I solved. works great.
library currency_text_input_formatter;
import 'dart:math';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
/// The `symbol` argument is used to symbol of NumberFormat.
/// Put '\$' for symbol
///
/// The `locale` argument is used to locale of NumberFormat.
/// Put 'en' or 'es' for locale
///
/// The `decimalDigits` argument is used to decimalDigits of NumberFormat.
/// Defaults `decimalDigits` is 2.
class CurrencyTextInputFormatter extends TextInputFormatter {
#override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, TextEditingValue newValue) {
if (newValue.text.isEmpty) {
return newValue.copyWith(text: '');
} else if (newValue.text == ".") {
return newValue.copyWith(
text: '0.00',
selection: TextSelection.collapsed(offset: 2),
);
} else {
NumberFormat f = NumberFormat("#,###,###.00", "en_US");
double newNumber = 0;
if ((!newValue.text.contains(".")) && oldValue.text.contains('.')) {
String tempString = newValue.text.replaceAll(f.symbols.GROUP_SEP, '');
tempString = tempString.substring(0, tempString.length - 2) +
"." +
tempString.substring(tempString.length - 2);
newNumber = double.parse(tempString);
} else {
newNumber = double.parse(newValue.text
.replaceAll(f.symbols.GROUP_SEP, '')
.replaceAll("..", '.'));
}
String newString = f.format(newNumber);
int cursorPosition = 0;
if (oldValue.text.length > newString.length) {
cursorPosition = -1;
} else if (oldValue.text.length < newString.length) {
cursorPosition = 1;
} else {
if (oldValue.text.replaceAll(f.symbols.GROUP_SEP, '').length >
newValue.text.replaceAll(f.symbols.GROUP_SEP, '').length) {
cursorPosition = -1;
if (newString == "0.00" && oldValue.selection.baseOffset == 0) {
newString = "";
}
} else if (oldValue.text.replaceAll(f.symbols.GROUP_SEP, '').length <
newValue.text.replaceAll(f.symbols.GROUP_SEP, '').length) {
cursorPosition = 1;
} else if (oldValue.selection.extentOffset >
oldValue.selection.baseOffset) {
cursorPosition =
oldValue.selection.baseOffset - oldValue.selection.extentOffset;
newString =
newString.substring(0, oldValue.selection.baseOffset - 1) +
newString.substring(oldValue.selection.baseOffset + 1);
newNumber = double.parse(newString
.replaceAll(f.symbols.GROUP_SEP, '')
.replaceAll("..", '.'));
newString = f.format(newNumber);
if (newString == "0.00" && oldValue.selection.baseOffset == 0) {
newString = "";
}
}
}
return TextEditingValue(
text: newString,
selection: TextSelection.collapsed(
offset: oldValue.selection.extent.offset +
cursorPosition +
(f.symbols.GROUP_SEP.allMatches(newString).length -
f.symbols.GROUP_SEP.allMatches(oldValue.text).length)),
);
}
}
}
Related
My problem is that I am working on an air app that communicates with each other through serversocket (server) socket (client)
When I test it in Air debug launcher everything works on the server side (I can see the server from a different internet connection)
But when I try to host from Android device it only works on LAN (can't see hosted server from the different connection)
My question is why it works in the Test environment but not in the built APP.. soo frustrating.
here is my serverside code:
package AS {
import flash.display.MovieClip;
import AS.Constants;
import flash.net.ServerSocket;
import flash.net.Socket;
import flash.events.ServerSocketConnectEvent;
import flash.events.ProgressEvent;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;
import flash.text.TextFieldType;
import flash.net.SharedObject;
import fl.data.DataProvider;
import flash.net.URLRequest;
import flash.media.Sound;
import flash.desktop.NativeApplication;
import flash.desktop.SystemIdleMode;
import flash.text.TextFormat;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.URLRequestMethod;
public class chatPage extends MovieClip {
private var server:ServerSocket;
private var clients:Vector.<Socket> = new Vector.<Socket>;
private var clientUsernames:Array = new Array();
private var autoScroll:Boolean=true;
private var autoClean:Boolean=false;
private var counter:int=900;
private var soundwarn:Boolean=true;
private var myformat:TextFormat=new TextFormat();
public function chatPage(address:String="0.0.0.0",port:uint=8888):void {
server = new ServerSocket();
server.bind(port,address);
server.addEventListener(ServerSocketConnectEvent.CONNECT, serverConnectHandler);
server.listen();
if(!server.listening){
die();
Constants.mainRef.initLoginScreen("not listening");
}else if(!server.bound){
die();
Constants.mainRef.initLoginScreen("not bound");
}
myformat.color=0xffffff;
client_list.setRendererStyle("textFormat",myformat);
soundButton.gotoAndStop(1);
chat_txt.text = String("");
chat_txt.scrollV=chat_txt.maxScrollV;
scrollBar.update();
scrollBar.addEventListener(Event.SCROLL, scrollingListener);
send_txt.addEventListener(KeyboardEvent.KEY_DOWN, commandHandler);
autoClean_btn.addEventListener(Event.CHANGE, autoCleanHandler);
soundButton.addEventListener(MouseEvent.CLICK, soundClickHandler);
close_btn.addEventListener(MouseEvent.CLICK, closeHandler);
kick_btn.addEventListener(MouseEvent.CLICK, kickHandler);
ban_btn.addEventListener(MouseEvent.CLICK, banHandler);
burn_btn.addEventListener(MouseEvent.CLICK, burnHandler);
share_btn.addEventListener(MouseEvent.CLICK, shareHandler);
scroll_down_btn.addEventListener(MouseEvent.CLICK, scrollDownHandler);
preventSleep_check.addEventListener(Event.CHANGE, sleepChangeHandler);
}
private function burnHandler(e:MouseEvent):void {
//burn all evidence for you and all your clients
if(chat_txt.length > 0){
send(4,Constants.mainRef.encrypt("burn"));
chat_txt.text = String("");
chat_txt.scrollV=chat_txt.maxScrollV;
scrollBar.update();
}
}
private function shareHandler(e:MouseEvent):void {
//share the contents of your chat_txt to all your clients
if(chat_txt.length > 0){
send(5,Constants.mainRef.encrypt(chat_txt.text));
}
}
private function banHandler(e:MouseEvent):void {
var tempIpArr:Array = new Array();
for (var i: uint = 0; i < clients.length; i++) {
tempIpArr.push(clients[i].remoteAddress);
}
Constants.STAGE.addChild(new listDialog(clientUsernames, tempIpArr, this) );
}
private function sleepChangeHandler(e:Event):void{
if(this.preventSleep_check.selected){
NativeApplication.nativeApplication.systemIdleMode = SystemIdleMode.KEEP_AWAKE;
}else{
NativeApplication.nativeApplication.systemIdleMode = SystemIdleMode.NORMAL;
}
}
private function kickHandler(e:MouseEvent):void {
if(client_list.selectedIndex > -1){
clients[client_list.selectedIndex].close();
clients[client_list.selectedIndex].removeEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
clients[client_list.selectedIndex].removeEventListener(Event.CLOSE, socketDisconnectHandler);
clients.splice(client_list.selectedIndex,1);
//send("▼"+clientUsernames[client_list.selectedIndex]);
send(3,String(clientUsernames[client_list.selectedIndex]));
clientUsernames.splice(client_list.selectedIndex,1);
client_list.dataProvider = new DataProvider( clientUsernames );
}
}
public function remoteKick(index:uint):void{
clients[index].close();
clients[index].removeEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
clients[index].removeEventListener(Event.CLOSE, socketDisconnectHandler);
clients.splice(index,1);
send(3,String(clientUsernames[index]));
clientUsernames.splice(index,1);
client_list.dataProvider = new DataProvider( clientUsernames );
}
private function scrollDownHandler(e:MouseEvent):void {
autoScroll=true;
chat_txt.scrollV=chat_txt.maxScrollV;
scrollBar.update();
}
private function closeHandler(e:MouseEvent):void {
die();
Constants.mainRef.initLoginScreen("Chat room terminated!");
//Constants.STAGE.addChild(new logInScreen("Chat room terminated!"));
}
private function soundClickHandler(e:MouseEvent):void {
if(soundButton.currentFrame == 1){
soundwarn=false;
soundButton.gotoAndStop(2);
}else{
soundwarn=true;
soundButton.gotoAndStop(1);
}
}
private function autoCleanFrameListener(e:Event):void {
if(autoClean){
counter--;
counter_txt.text = String( Math.floor( counter / 30 ) + "s" );
if(counter <= 0){
counter_txt.text = String("30s");
chat_txt.text = String("");
chat_txt.scrollV=chat_txt.maxScrollV;
scrollBar.update();
currentDataStr = String("");
counter=900;
}
}
}
private function autoCleanHandler(e:Event):void {
if(autoClean_btn.selected){
autoClean=true;
counter_txt.text = String("30s");
this.addEventListener(Event.ENTER_FRAME, autoCleanFrameListener);
}else{
this.removeEventListener(Event.ENTER_FRAME, autoCleanFrameListener);
autoClean=false;
counter_txt.text = String("");
counter=900;
}
}
private function scrollingListener(e:Event):void {
if(chat_txt.scrollV!=chat_txt.maxScrollV){
autoScroll=false;
}
}
private function serverConnectHandler(e:ServerSocketConnectEvent):void {
var socket:Socket = e.socket;
var banned:Boolean;
if(Constants.banList.length > 0){
for (var i: uint = 0; i < Constants.banList.length; i++) {
if(Constants.banList[i] == socket.remoteAddress){
banned=true;
break;
}else{
banned=false;
}
}
}else{
banned=false;
}
if(!banned){
clients.push(socket);
clients[clients.length-1].addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
clients[clients.length-1].addEventListener(Event.CLOSE, socketDisconnectHandler);
send(2,Constants.mainRef.encrypt(Constants.mainRef.username));
}else{
socket.close();
}
}
private function socketDisconnectHandler(e:Event):void {
send(3,Constants.mainRef.encrypt( clientUsernames[clients.indexOf(e.target)] ) );
clientUsernames.splice(clients.indexOf(e.target),1);
client_list.dataProvider = new DataProvider( clientUsernames );
clients.splice(clients.indexOf(e.target),1);
e.target.close();
e.target.removeEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
e.target.removeEventListener(Event.CLOSE, socketDisconnectHandler);
}
private var currentDataStr:String;
private var currentDataType:uint;
private function socketDataHandler(e:ProgressEvent):void {
var socket:Socket = e.currentTarget as Socket;
currentDataType = socket.readUnsignedInt();
currentDataStr = socket.readUTFBytes(socket.bytesAvailable);
send(currentDataType, currentDataStr);
if(currentDataType == 1){
chat_txt.appendText(Constants.mainRef.decrypt(currentDataStr) );
if(autoScroll){
chat_txt.scrollV=chat_txt.maxScrollV;
}
scrollBar.update();
if(soundwarn){
//give sound warning
var snd:Sound = new Sound(new URLRequest("sound/ding.mp3"));
snd.play();
}
}else if(currentDataType == 2){
var tempString:String = Constants.mainRef.decrypt(currentDataStr);
clientUsernames.push(tempString);
client_list.dataProvider = new DataProvider( clientUsernames );
}
tempString=String("");
currentDataStr=String("");
currentDataType=0;
}
private function commandHandler(e:KeyboardEvent):void {
if(e.keyCode==13){
//ENTER GOT PRESSED
var commandStr:String = send_txt.text;
if(commandStr.indexOf(".") == 0){
if(commandStr.indexOf(".del") > -1 ){
chat_txt.text = String("");
currentDataStr = String("");
chat_txt.scrollV=chat_txt.maxScrollV;
scrollBar.update();
}else if(commandStr.indexOf(".burn") > -1 ){
if(chat_txt.length > 0){
send(4,Constants.mainRef.encrypt("burn"));
chat_txt.text = String("");
chat_txt.scrollV=chat_txt.maxScrollV;
scrollBar.update();
}
}else if(commandStr.indexOf(".share") > -1 ){
if(chat_txt.length > 0){
send(5,Constants.mainRef.encrypt(chat_txt.text));
}
}else if(commandStr.indexOf(".ip") > -1 ){
getIpOnline();
}else if(commandStr.indexOf(".roll") > -1 ){
var rngMax:int = parseInt( commandStr.slice(commandStr.indexOf(" ")) );
if(rngMax > 0){
var rawString:String = Constants.mainRef.username + " rolled " + String(Constants.mainRef.randomNum(1,rngMax)) + " out of " + String(rngMax) + "\n";
send(1, Constants.mainRef.encrypt( rawString ) );
chat_txt.appendText( rawString );
if(autoScroll){
chat_txt.scrollV=chat_txt.maxScrollV;
}
scrollBar.update();
}
}else if(commandStr.indexOf(".kick") > -1 && client_list.selectedIndex > -1){
clients[client_list.selectedIndex].close();
clients[client_list.selectedIndex].removeEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
clients[client_list.selectedIndex].removeEventListener(Event.CLOSE, socketDisconnectHandler);
clients.splice(client_list.selectedIndex,1);
send(3,Constants.mainRef.encrypt( clientUsernames[client_list.selectedIndex] ) );
clientUsernames.splice(client_list.selectedIndex,1);
client_list.dataProvider = new DataProvider( clientUsernames );
}
}else if(commandStr.length > 0){
send(1, Constants.mainRef.encrypt(Constants.mainRef.username + ": " + commandStr + "\n"));
chat_txt.appendText(Constants.mainRef.username + ": " + commandStr + "\n");
if(autoScroll){
chat_txt.scrollV=chat_txt.maxScrollV;
}
scrollBar.update();
}
send_txt.text = String("");
commandStr = String("");
Constants.STAGE.focus = null;
}
}
public function send(typeIndex:uint, data:String):void {
for each(var client:Socket in clients){
client.writeUnsignedInt(typeIndex);
client.writeUTFBytes(data);
client.flush();
}
}
private function getIpOnline():void{
var phpFileRequest:URLRequest = new URLRequest("https://api.ipify.org/");
phpFileRequest.method = URLRequestMethod.GET;
var phpLoader:URLLoader = new URLLoader();
phpLoader.addEventListener(Event.COMPLETE, showResult);
phpLoader.load(phpFileRequest);
}
private function showResult(e:Event):void{
send_txt.text = String(e.target.data);
e.target.removeEventListener(Event.COMPLETE, showResult);
}
public function die():void{
var i:uint
for(i = 0; i < clients.length; i++) {
clients[i].close();
clients[i].removeEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
clients[i].removeEventListener(Event.CLOSE, socketDisconnectHandler);
}
server.removeEventListener(ServerSocketConnectEvent.CONNECT, serverConnectHandler);
server.close();
chat_txt.text = String("");
send_txt.text = String("");
kick_btn.removeEventListener(MouseEvent.CLICK, kickHandler);
ban_btn.removeEventListener(MouseEvent.CLICK, banHandler);
preventSleep_check.removeEventListener(Event.CHANGE, sleepChangeHandler);
close_btn.removeEventListener(MouseEvent.CLICK, closeHandler);
burn_btn.removeEventListener(MouseEvent.CLICK, burnHandler);
share_btn.removeEventListener(MouseEvent.CLICK, shareHandler);
scroll_down_btn.removeEventListener(MouseEvent.CLICK, scrollDownHandler);
soundButton.removeEventListener(MouseEvent.CLICK, soundClickHandler);
autoClean_btn.removeEventListener(Event.CHANGE, autoCleanHandler);
this.removeEventListener(Event.ENTER_FRAME, autoCleanFrameListener);
scrollBar.removeEventListener(Event.SCROLL, scrollingListener);
send_txt.removeEventListener(KeyboardEvent.KEY_DOWN, commandHandler);
clients.length=0;
clientUsernames.length=0;
if(Constants.cardIndexer.length > 0){
for (i = 0; i < Constants.cardIndexer.length; i++) {
Constants.cardIndexer[i].die(4);
}
Constants.cardIndexer.length=0;
Constants.deckRef.length=0;
}
this.parent.removeChild(this);
}
private function chatText(texty:String,chat:Boolean=true):void{
if(chat){
send(1, Constants.mainRef.encrypt(Constants.mainRef.username + ": " + texty + "\n"));
chat_txt.appendText(Constants.mainRef.username + ": " + texty + "\n");
if(autoScroll){
chat_txt.scrollV=chat_txt.maxScrollV;
}
scrollBar.update();
}else{
send(1, Constants.mainRef.encrypt(texty + "\n"));
chat_txt.appendText(texty + "\n");
if(autoScroll){
chat_txt.scrollV=chat_txt.maxScrollV;
}
scrollBar.update();
}
}
}
}
For those who will struggle with this problem in the future.
Mainly 2 things required to be able to host a socket server successfully visible from
the internet:
-port forwarding.
-put your air app in firewall "allow" list.
(in my situation this was the missing part. ouch!)
Now everything works as it should.
I want to show my numbers in money format and separate digits like the example below:
1000 -----> 1,000
10000 -----> 10,000
100000 -----> 100,000
1000000 -----> 1,000,000
Thanks
Another approach :
NumberFormat format = NumberFormat.getCurrencyInstance();
format.setMaximumFractionDigits(0);
format.setCurrency(Currency.getInstance("EUR"));
format.format(1000000);
This way, it's displaying 1 000 000 € or 1,000,000 €, depending on device currency's display settings
You need to use a number formatter, like so:
NumberFormat formatter = new DecimalFormat("#,###");
double myNumber = 1000000;
String formattedNumber = formatter.format(myNumber);
//formattedNumber is equal to 1,000,000
Hope this helps!
double number = 1000000000.0;
String COUNTRY = "US";
String LANGUAGE = "en";
String str = NumberFormat.getCurrencyInstance(new Locale(LANGUAGE, COUNTRY)).format(number);
//str = $1,000,000,000.00
Currency formatter.
public static String currencyFormat(String amount) {
DecimalFormat formatter = new DecimalFormat("###,###,##0.00");
return formatter.format(Double.parseDouble(amount));
}
Use this:
int number = 1000000000;
String str = NumberFormat.getNumberInstance(Locale.US).format(number);
//str = 1,000,000,000
This Method gives you the exact output which you need:
public String currencyFormatter(String num) {
double m = Double.parseDouble(num);
DecimalFormat formatter = new DecimalFormat("###,###,###");
return formatter.format(m);
}
Try the following solution:
NumberFormat format = NumberFormat.getCurrencyInstance();
((TextView)findViewById(R.id.text_result)).setText(format.format(result));
The class will return a formatter for the device default currency.
You can refer to this link for more information:
https://developer.android.com/reference/java/text/NumberFormat.html
Here's a kotlin Extension that converts a Double to a Currency(Nigerian Naira)
fun Double.toRidePrice():String{
val format: NumberFormat = NumberFormat.getCurrencyInstance()
format.maximumFractionDigits = 0
format.currency = Currency.getInstance("NGN")
return format.format(this.roundToInt())
}
Use a Formatter class
For eg:
String s = (String.format("%,d", 1000000)).replace(',', ' ');
Look into:
http://developer.android.com/reference/java/util/Formatter.html
The way that I do this in our app is this:
amount.addTextChangedListener(new CurrencyTextWatcher(amount));
And the CurrencyTextWatcher is this:
public class CurrencyTextWatcher implements TextWatcher {
private EditText ed;
private String lastText;
private boolean bDel = false;
private boolean bInsert = false;
private int pos;
public CurrencyTextWatcher(EditText ed) {
this.ed = ed;
}
public static String getStringWithSeparator(long value) {
DecimalFormat formatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US);
String f = formatter.format(value);
return f;
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
bDel = false;
bInsert = false;
if (before == 1 && count == 0) {
bDel = true;
pos = start;
} else if (before == 0 && count == 1) {
bInsert = true;
pos = start;
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
lastText = s.toString();
}
#Override
public void afterTextChanged(Editable s) {
ed.removeTextChangedListener(this);
StringBuilder sb = new StringBuilder();
String text = s.toString();
for (int i = 0; i < text.length(); i++) {
if ((text.charAt(i) >= 0x30 && text.charAt(i) <= 0x39) || text.charAt(i) == '.' || text.charAt(i) == ',')
sb.append(text.charAt(i));
}
if (!sb.toString().equals(s.toString())) {
bDel = bInsert = false;
}
String newText = getFormattedString(sb.toString());
s.clear();
s.append(newText);
ed.addTextChangedListener(this);
if (bDel) {
int idx = pos;
if (lastText.length() - 1 > newText.length())
idx--; // if one , is removed
if (idx < 0)
idx = 0;
ed.setSelection(idx);
} else if (bInsert) {
int idx = pos + 1;
if (lastText.length() + 1 < newText.length())
idx++; // if one , is added
if (idx > newText.length())
idx = newText.length();
ed.setSelection(idx);
}
}
private String getFormattedString(String text) {
String res = "";
try {
String temp = text.replace(",", "");
long part1;
String part2 = "";
int dotIndex = temp.indexOf(".");
if (dotIndex >= 0) {
part1 = Long.parseLong(temp.substring(0, dotIndex));
if (dotIndex + 1 <= temp.length()) {
part2 = temp.substring(dotIndex + 1).trim().replace(".", "").replace(",", "");
}
} else
part1 = Long.parseLong(temp);
res = getStringWithSeparator(part1);
if (part2.length() > 0)
res += "." + part2;
else if (dotIndex >= 0)
res += ".";
} catch (Exception ex) {
ex.printStackTrace();
}
return res;
}
Now if you add this watcher to your EditText, as soon as user enter his number, the watcher decides whether it needs separator or not.
i used this code for my project and it works:
EditText edt_account_amount = findViewById(R.id.edt_account_amount);
edt_account_amount.addTextChangedListener(new DigitFormatWatcher(edt_account_amount));
and defined class:
public class NDigitCardFormatWatcher implements TextWatcher {
EditText et_filed;
String processed = "";
public NDigitCardFormatWatcher(EditText et_filed) {
this.et_filed = et_filed;
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void afterTextChanged(Editable editable) {
String initial = editable.toString();
if (et_filed == null) return;
if (initial.isEmpty()) return;
String cleanString = initial.replace(",", "");
NumberFormat formatter = new DecimalFormat("#,###");
double myNumber = new Double(cleanString);
processed = formatter.format(myNumber);
//Remove the listener
et_filed.removeTextChangedListener(this);
//Assign processed text
et_filed.setText(processed);
try {
et_filed.setSelection(processed.length());
} catch (Exception e) {
// TODO: handle exception
}
//Give back the listener
et_filed.addTextChangedListener(this);
}
}
Updated 2022 answer
Try this snippet. It formats a number in string complete with the currency & setting fractional digits.
Upvote if this helped you! :)
/**
* Formats amount in string to human-readable amount (separated with commas
* & prepends currency symbol)
*
* #param amount The amount to format in String
* #return The formatted amount complete with separators & currency symbol added
*/
public static String formatCurrency(String amount) {
String formattedAmount = amount;
try {
if (amount == null || amount.isEmpty())
throw new Exception("Amount is null/empty");
Double amountInDouble = Double.parseDouble(amount);
NumberFormat numberFormat = NumberFormat.getCurrencyInstance(new Locale("en", "IN"));
numberFormat.setMaximumFractionDigits(2);
numberFormat.setMinimumFractionDigits(2);
formattedAmount = numberFormat.format(amountInDouble);
} catch (Exception exception) {
exception.printStackTrace();
return formattedAmount;
}
return formattedAmount;
}
private val currencyFormatter = NumberFormat.getCurrencyInstance(LOCALE_AUS).configure()
private fun NumberFormat.configure() = apply {
maximumFractionDigits = 2
minimumFractionDigits = 2
}
fun Number.asCurrency(): String {
return currencyFormatter.format(this)
}
And then just use as
val x = 100000.234
x.asCurrency()
If you have the value stored in a String like me, which was coming from the server like "$20000.00".
You can do something like this in Kotlin (JetpackCompose):
#Composable
fun PrizeAmount(
modifier: Modifier = Modifier,
prize: String,
)
{
val currencyFormat = NumberFormat.getCurrencyInstance(Locale("en", "US"))
val text = currencyFormat.format(prize.substringAfter("$").toDouble())
...
}
Output: "$20,000.00"
NumberFormat.getCurrencyInstance(Locale("ES", "es")).format(number)
here is a kotlin version to Format Currency, here i'm getting an argument from another fragment from an input Field then it will be set in the textView in the main Fragment
fun formatArgumentCurrency(argument : String, textView: TextView) {
val valueText = requireArguments().get(argument).toString()
val dec = DecimalFormat("#,###.##")
val number = java.lang.Double.valueOf(valueText)
val value = dec.format(number)
val currency = Currency.getInstance("USD")
val symbol = currency.symbol
textView.text = String.format("$symbol$value","%.2f" )
}
You can easily achieve this with this small simple library.
https://github.com/jpvs0101/Currencyfy
Just pass any number, then it will return formatted string, just like that.
currencyfy (500000.78); // $ 500,000.78 //default
currencyfy (500000.78, false); // $ 500,001 // hide fraction (will round off automatically!)
currencyfy (500000.78, false, false); // 500,001 // hide fraction & currency symbol
currencyfy (new Locale("en", "in"), 500000.78); // ₹ 5,00,000.78 // custom locale
It compatible with all versions of Android including older versions!
How to compare app version in android
I got latest version code and current version code , but the problem is
current version is 1.0
and latest version is 1.0.0
so how to compare that float value in android
I have written a small Android library for comparing version numbers: https://github.com/G00fY2/version-compare
What it basically does is this:
public int compareVersions(String versionA, String versionB) {
String[] versionTokensA = versionA.split("\\.");
String[] versionTokensB = versionB.split("\\.");
List<Integer> versionNumbersA = new ArrayList<>();
List<Integer> versionNumbersB = new ArrayList<>();
for (String versionToken : versionTokensA) {
versionNumbersA.add(Integer.parseInt(versionToken));
}
for (String versionToken : versionTokensB) {
versionNumbersB.add(Integer.parseInt(versionToken));
}
final int versionASize = versionNumbersA.size();
final int versionBSize = versionNumbersB.size();
int maxSize = Math.max(versionASize, versionBSize);
for (int i = 0; i < maxSize; i++) {
if ((i < versionASize ? versionNumbersA.get(i) : 0) > (i < versionBSize ? versionNumbersB.get(i) : 0)) {
return 1;
} else if ((i < versionASize ? versionNumbersA.get(i) : 0) < (i < versionBSize ? versionNumbersB.get(i) : 0)) {
return -1;
}
}
return 0;
}
This snippet doesn't offer any error checks or handling. Beside that my library also supports suffixes like "1.2-rc" > "1.2-beta".
I am a bit late to the party but I have a great solution for all of you!
1. Use this class:
public class VersionComparator implements Comparator {
public boolean equals(Object o1, Object o2) {
return compare(o1, o2) == 0;
}
public int compare(Object o1, Object o2) {
String version1 = (String) o1;
String version2 = (String) o2;
VersionTokenizer tokenizer1 = new VersionTokenizer(version1);
VersionTokenizer tokenizer2 = new VersionTokenizer(version2);
int number1, number2;
String suffix1, suffix2;
while (tokenizer1.MoveNext()) {
if (!tokenizer2.MoveNext()) {
do {
number1 = tokenizer1.getNumber();
suffix1 = tokenizer1.getSuffix();
if (number1 != 0 || suffix1.length() != 0) {
// Version one is longer than number two, and non-zero
return 1;
}
}
while (tokenizer1.MoveNext());
// Version one is longer than version two, but zero
return 0;
}
number1 = tokenizer1.getNumber();
suffix1 = tokenizer1.getSuffix();
number2 = tokenizer2.getNumber();
suffix2 = tokenizer2.getSuffix();
if (number1 < number2) {
// Number one is less than number two
return -1;
}
if (number1 > number2) {
// Number one is greater than number two
return 1;
}
boolean empty1 = suffix1.length() == 0;
boolean empty2 = suffix2.length() == 0;
if (empty1 && empty2) continue; // No suffixes
if (empty1) return 1; // First suffix is empty (1.2 > 1.2b)
if (empty2) return -1; // Second suffix is empty (1.2a < 1.2)
// Lexical comparison of suffixes
int result = suffix1.compareTo(suffix2);
if (result != 0) return result;
}
if (tokenizer2.MoveNext()) {
do {
number2 = tokenizer2.getNumber();
suffix2 = tokenizer2.getSuffix();
if (number2 != 0 || suffix2.length() != 0) {
// Version one is longer than version two, and non-zero
return -1;
}
}
while (tokenizer2.MoveNext());
// Version two is longer than version one, but zero
return 0;
}
return 0;
}
// VersionTokenizer.java
public static class VersionTokenizer {
private final String _versionString;
private final int _length;
private int _position;
private int _number;
private String _suffix;
private boolean _hasValue;
VersionTokenizer(String versionString) {
if (versionString == null)
throw new IllegalArgumentException("versionString is null");
_versionString = versionString;
_length = versionString.length();
}
public int getNumber() {
return _number;
}
String getSuffix() {
return _suffix;
}
public boolean hasValue() {
return _hasValue;
}
boolean MoveNext() {
_number = 0;
_suffix = "";
_hasValue = false;
// No more characters
if (_position >= _length)
return false;
_hasValue = true;
while (_position < _length) {
char c = _versionString.charAt(_position);
if (c < '0' || c > '9') break;
_number = _number * 10 + (c - '0');
_position++;
}
int suffixStart = _position;
while (_position < _length) {
char c = _versionString.charAt(_position);
if (c == '.') break;
_position++;
}
_suffix = _versionString.substring(suffixStart, _position);
if (_position < _length) _position++;
return true;
}
}
}
2. create this function
private fun isNewVersionAvailable(currentVersion: String, latestVersion: String): Boolean {
val versionComparator = VersionComparator()
val result: Int = versionComparator.compare(currentVersion, latestVersion)
var op = "=="
if (result < 0) op = "<"
if (result > 0) op = ">"
System.out.printf("%s %s %s\n", currentVersion, op, latestVersion)
return if (op == ">" || op == "==") {
false
} else op == "<"
}
3. and just call it by
e.g. isNewVersionAvailable("1.2.8","1.2.9") where 1.2.8 is your current version here and 1.2.9 is the latest version, which returns true!
Why overcomplicate this so much?
Just scale the major, minor, patch version and you have it covered:
fun getAppVersionFromString(version: String): Int { // "2.3.5"
val versions = version.split(".") // [2, 3, 5]
val major = versions[0].toIntOrDefault(0) * 10000 // 20000
val minor = versions[1].toIntOrDefault(0) * 1000 // 3000
val patch = versions[2].toIntOrDefault(0) * 100 // 500
return major + minor + patch // 2350
}
That way when you compare e.g 9.10.10 with 10.0.0 the second one is greater.
Use the following method to compare the versions number:
Convert float to String first.
public static int versionCompare(String str1, String str2) {
String[] vals1 = str1.split("\\.");
String[] vals2 = str2.split("\\.");
int i = 0;
// set index to first non-equal ordinal or length of shortest version string
while (i < vals1.length && i < vals2.length && vals1[i].equals(vals2[i])) {
i++;
}
// compare first non-equal ordinal number
if (i < vals1.length && i < vals2.length) {
int diff = Integer.valueOf(vals1[i]).compareTo(Integer.valueOf(vals2[i]));
return Integer.signum(diff);
}
// the strings are equal or one string is a substring of the other
// e.g. "1.2.3" = "1.2.3" or "1.2.3" < "1.2.3.4"
return Integer.signum(vals1.length - vals2.length);
}
Refer the following SO question : Efficient way to compare version strings in Java
I use the follow code to parse price from Google Play In-app Billing:
private static Number parsePrice(String priceFromGoogle) {
Locale currencyLocale = getCurrencyLocale(priceFromGoogle);
NumberFormat numberFormat = NumberFormat.getCurrencyInstance(currencyLocale);
Number number = null;
try {
number = numberFormat.parse(priceFromGoogle);
} catch (ParseException e) {
e.printStackTrace();
}
return number;
}
private Locale getCurrencyLocale(String price) {
Locale locale = null;
for (Locale availableLocale : Locale.getAvailableLocales()) {
NumberFormat numberFormat = NumberFormat.getCurrencyInstance(availableLocale);
try {
numberFormat.parse(price);
locale = availableLocale;
break;
} catch (ParseException e) {
//do nothing
}
}
return locale;
}
It works fine on my test devices and in my locale. But on some devices and in some countries I encounter prices like this: "Php1,337.07", "US$ 29.99", "MX$374.79". My approach doesn't work in this case.
Is there an universal approach to solve this problem?
Check their In-app billing sample project and modify SkuDetails.java so that you can get that information as well:
import org.json.JSONException;
import org.json.JSONObject;
/**
* Represents an in-app product's listing details.
*/
public class SkuDetails {
String mItemType;
String mSku;
String mType;
int mPriceAmountMicros;
String mPriceCurrencyCode;
String mPrice;
String mTitle;
String mDescription;
String mJson;
public SkuDetails(String jsonSkuDetails) throws JSONException {
this(IabHelper.ITEM_TYPE_INAPP, jsonSkuDetails);
}
public SkuDetails(String itemType, String jsonSkuDetails) throws JSONException {
mItemType = itemType;
mJson = jsonSkuDetails;
JSONObject o = new JSONObject(mJson);
mSku = o.optString("productId");
mType = o.optString("type");
mPrice = o.optString("price");
mPriceAmountMicros = o.optInt("price_amount_micros");
mPriceCurrencyCode = o.optString("price_currency_code");
mTitle = o.optString("title");
mDescription = o.optString("description");
}
public String getSku() { return mSku; }
public String getType() { return mType; }
public String getPrice() { return mPrice; }
public String getTitle() { return mTitle; }
public String getDescription() { return mDescription; }
public int getPriceAmountMicros() { return mPriceAmountMicros; }
public String getPriceCurrencyCode() { return mPriceCurrencyCode; }
#Override
public String toString() {
return "SkuDetails:" + mJson;
}
}
You can get the price in micros in the JSON retrieved by IabHelper.
This is not officially documented but here is how I've done it by editing SkuDetails.java :
public class SkuDetails {
...
Double mPriceMicros;
public SkuDetails(String itemType, String jsonSkuDetails) throws JSONException {
...
String priceMicros = o.optString("price_amount_micros");
if (priceMicros != null) {
String format = new StringBuilder(priceMicros).insert(priceMicros.length() - 6, ".").toString();
mPriceMicros = Double.parseDouble(format);
}
}
...
public Double getPriceMicros() { return mPriceMicros; }
}
Hope this helps !
PS : I tried your Price class but it parsed 0.8 for 0,89 €
As Google Play may return prices in currency format which is unsupported by java.text.NumberFormat, I wrote my own implementation
public class Price {
private double value;
private String currency;
private String pattern;
private DecimalFormat decimalFormat;
private Price() {}
private static String currencyToDecimalFormat(String value, Price price) {
char decimalSeparator = '.';
char groupingSeparator = 0;
if (value.length() >= 3) {
char[] chars = value.toCharArray();
if (chars[chars.length - 2] == ',') {
decimalSeparator = ',';
chars[chars.length - 2] = '.';
} else if (chars[chars.length - 3] == ',') {
decimalSeparator = ',';
chars[chars.length - 3] = '.';
}
value = new String(chars);
}
if (value.contains(",")) {
groupingSeparator = ',';
value = value.replaceAll(",", "");
} else if (value.contains(" ")) {
groupingSeparator = ' ';
value = value.replaceAll(" ", "");
} else if (value.contains("\u00A0")) {
groupingSeparator = '\u00A0';
value = value.replaceAll("\u00A0", "");
}
DecimalFormatSymbols symbols = new DecimalFormatSymbols();
if (groupingSeparator != 0) {
price.decimalFormat = new DecimalFormat("###,###.00");
symbols.setGroupingSeparator(groupingSeparator);
} else {
price.decimalFormat = new DecimalFormat("######.00");
}
symbols.setDecimalSeparator(decimalSeparator);
price.decimalFormat.setDecimalFormatSymbols(symbols);
return value.replaceAll(",", "");
}
public static Price parsePrice(String priceFromGoogle) {
Price price = new Price();
StringBuilder patternBuilder = new StringBuilder();
Pattern pattern = Pattern.compile("(?:[0-9]{1,3})(?:[0-9,.\\s\u00A0]+)");
Matcher matcher = pattern.matcher(priceFromGoogle);
matcher.find();
String priceString = matcher.group();
if (priceFromGoogle.indexOf(priceString) == 0) {
if (priceFromGoogle.length() != priceString.length()) {
price.currency = priceFromGoogle.substring(priceString.length());
} else {
price.currency = "";
}
} else {
price.currency = priceFromGoogle.substring(0, priceFromGoogle.indexOf(priceString));
}
price.currency = price.currency.trim();
if (priceFromGoogle.startsWith(price.currency)) {
patternBuilder.append("%1s");
char nextChar = priceFromGoogle.charAt(price.currency.length());
if (nextChar == ' ' || nextChar == 0xA0) {
patternBuilder.append(' ');
}
patternBuilder.append("%2$s");
} else {
patternBuilder.append("%2$s");
char prevChar = priceFromGoogle.charAt(priceFromGoogle.indexOf(price.currency) - 1);
if (prevChar == ' ' || prevChar == 0xA0) {
patternBuilder.append(' ');
}
patternBuilder.append("%1s");
}
price.pattern = patternBuilder.toString();
priceString = trim(priceString);
priceString = currencyToDecimalFormat(priceString, price);
price.value = Double.parseDouble(priceString);
return price;
}
#Override
public String toString() {
if (pattern != null) {
return String.format(pattern, currency, decimalFormat.format(value));
} else {
return "";
}
}
}
EDIT1:
Because of Google uses non-breaking space instead of usual space you need check this and use custom trim function:
public static String trim(String text) {
int start = 0, last = text.length() - 1;
int end = last;
while ((start <= end) && (text.charAt(start) <= ' ' || text.charAt(start) == 0xA0)) {
start++;
}
while ((end >= start) && (text.charAt(end) <= ' ' || text.charAt(end) == 0xA0)) {
end--;
}
if (start == 0 && end == last) {
return text;
}
return text.substring(start, end);
}
Can someone please help me with some code I have it is supposed to check that the string being passed is of 2 string and 3 ints which works fine, but if the 1 int is a zero it doesn't work
so if it was CM044 it won't work, CM450 will work can someone please help.
public boolean checkModule(String Module) {
if(Module.length() == 5){
boolean hasString = false;
boolean hasInt = false;
String letters = Module.substring(0, 2);
Pattern p = Pattern.compile("^[a-zA-Z]+$");
Matcher m = p.matcher(letters);
if (m.matches()) {
hasString = true;
}
String numbers=Module.substring(2,5);
try {
int num = Integer.parseInt(numbers);
String n = num + "";
if (num >0 && n.length() == 3)
hasInt = true;
} catch (Exception e) {
}
if (hasInt && hasString) {
return true;
}
}else{
return false;
}
return false;
}
Thanks
If you are going to use regular expressions you should definitely stick with them and not vary in and out.
package com.examples;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
/**
* #param args
*/
public static void main(String[] args) {
new Main();
}
public Main() {
String[] testInputs = new String[] {"CM045", "CM450"};
for(String input : testInputs) {
System.out.println("The module " + input + " is " + (checkModule(input) ? "valid" : "invalid"));
}
}
public boolean checkModule(String Module){
Pattern p = Pattern.compile("[A-Z]{2}[0-9]{3}");
Matcher m = p.matcher(Module.toUpperCase());
return m.matches();
}
}
if the String is "045" the Integer value is 45 and so the length of num can't be 3
Use this
if(num>=0) {
hasInt = true;
}
and it has to work