本文整理汇总了Java中com.google.bitcoin.core.Wallet.BalanceType类的典型用法代码示例。如果您正苦于以下问题:Java BalanceType类的具体用法?Java BalanceType怎么用?Java BalanceType使用的例子?那么恭喜您, 这里精选的类代码示例或许可以为您提供帮助。
BalanceType类属于com.google.bitcoin.core.Wallet包,在下文中一共展示了BalanceType类的14个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的Java代码示例。
示例1: notifyWidgets
import com.google.bitcoin.core.Wallet.BalanceType; //导入依赖的package包/类
public void notifyWidgets()
{
final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
final ComponentName providerName = new ComponentName(this, WalletBalanceWidgetProvider.class);
try
{
final int[] appWidgetIds = appWidgetManager.getAppWidgetIds(providerName);
if (appWidgetIds.length > 0)
{
final Wallet wallet = application.getWallet();
final BigInteger balance = wallet.getBalance(BalanceType.ESTIMATED);
WalletBalanceWidgetProvider.updateWidgets(this, appWidgetManager, appWidgetIds, balance);
}
}
catch (final RuntimeException x) // system server dead?
{
log.warn("cannot update app widgets", x);
}
}
开发者ID:9cat,项目名称:templecoin-android-wallet,代码行数:24,代码来源:BlockchainServiceImpl.java
示例2: testReceiveCoinbaseTransaction
import com.google.bitcoin.core.Wallet.BalanceType; //导入依赖的package包/类
@Test
public void testReceiveCoinbaseTransaction() throws Exception {
// Block 169482 (hash 0000000000000756935f1ee9d5987857b604046f846d3df56d024cdb5f368665)
// contains coinbase transactions that are mining pool shares.
// The private key MINERS_KEY is used to check transactions are received by a wallet correctly.
byte[] blockAsBytes = getBytes(getClass().getResourceAsStream("block169482.dat"));
// Create block 169482.
Block block = new Block(params, blockAsBytes);
// Check block.
assertNotNull(block);
block.verify();
assertEquals(BLOCK_NONCE, block.getNonce());
StoredBlock storedBlock = new StoredBlock(block, BigInteger.ONE, BLOCK_OF_INTEREST); // Nonsense work - not used in test.
// Create a wallet contain the miner's key that receives a spend from a coinbase.
ECKey miningKey = (new DumpedPrivateKey(params, MINING_PRIVATE_KEY)).getKey();
assertNotNull(miningKey);
Wallet wallet = new Wallet(params);
wallet.addKey(miningKey);
// Initial balance should be zero by construction.
assertEquals(BigInteger.ZERO, wallet.getBalance());
// Give the wallet the first transaction in the block - this is the coinbase tx.
List<Transaction> transactions = block.getTransactions();
assertNotNull(transactions);
wallet.receiveFromBlock(transactions.get(0), storedBlock, NewBlockType.BEST_CHAIN, 0);
// Coinbase transaction should have been received successfully but be unavailable to spend (too young).
assertEquals(BALANCE_AFTER_BLOCK, wallet.getBalance(BalanceType.ESTIMATED));
assertEquals(BigInteger.ZERO, wallet.getBalance(BalanceType.AVAILABLE));
}
开发者ID:HashEngineering,项目名称:megacoinj,代码行数:38,代码来源:CoinbaseBlockTest.java
示例3: onUpdate
import com.google.bitcoin.core.Wallet.BalanceType; //导入依赖的package包/类
@Override
public void onUpdate(final Context context, final AppWidgetManager appWidgetManager, final int[] appWidgetIds)
{
final WalletApplication application = (WalletApplication) context.getApplicationContext();
final Wallet wallet = application.getWallet();
final BigInteger balance = wallet.getBalance(BalanceType.ESTIMATED);
updateWidgets(context, appWidgetManager, appWidgetIds, balance);
}
开发者ID:9cat,项目名称:templecoin-android-wallet,代码行数:10,代码来源:WalletBalanceWidgetProvider.java
示例4: updateView
import com.google.bitcoin.core.Wallet.BalanceType; //导入依赖的package包/类
private void updateView()
{
balance = application.getWallet().getBalance(BalanceType.ESTIMATED);
if (adapter != null)
{
final String precision = prefs.getString(Constants.PREFS_KEY_BTC_PRECISION, Constants.PREFS_DEFAULT_BTC_PRECISION);
final int btcShift = precision.length() == 3 ? precision.charAt(2) - '0' : 0;
final BigInteger base = btcShift == 0 ? GenericUtils.ONE_BTC : GenericUtils.ONE_MBTC;
adapter.setRateBase(base);
}
}
开发者ID:9cat,项目名称:templecoin-android-wallet,代码行数:15,代码来源:ExchangeRatesFragment.java
示例5: getActiveWalletEstimatedBalance
import com.google.bitcoin.core.Wallet.BalanceType; //导入依赖的package包/类
/**
* Get the estimated balance of the active wallet.
*
* @return The estimated balance
*/
public BigInteger getActiveWalletEstimatedBalance() {
if (activeWalletModelData.getWallet() == null) {
return BigInteger.ZERO;
} else {
return activeWalletModelData.getWallet().getBalance(BalanceType.ESTIMATED);
}
}
开发者ID:coinspark,项目名称:sparkbit,代码行数:13,代码来源:BitcoinModel.java
示例6: getActiveWalletAvailableBalance
import com.google.bitcoin.core.Wallet.BalanceType; //导入依赖的package包/类
/**
* Get the available balance (plus boomeranged change) of the active wallet.
*
* @return the available balance
*/
public BigInteger getActiveWalletAvailableBalance() {
if (activeWalletModelData.getWallet() == null) {
return BigInteger.ZERO;
} else {
return activeWalletModelData.getWallet().getBalance(BalanceType.AVAILABLE);
}
}
开发者ID:coinspark,项目名称:sparkbit,代码行数:13,代码来源:BitcoinModel.java
示例7: testReceiveCoinbaseTransaction
import com.google.bitcoin.core.Wallet.BalanceType; //导入依赖的package包/类
@Test
public void testReceiveCoinbaseTransaction() throws Exception {
// Block 169482 (hash 0000000000000756935f1ee9d5987857b604046f846d3df56d024cdb5f368665)
// contains coinbase transactions that are mining pool shares.
// The private key MINERS_KEY is used to check transactions are received by a wallet correctly.
byte[] blockAsBytes = getBytes(getClass().getResourceAsStream("block169482.dat"));
// Create block 169482.
Block block = new Block(params, blockAsBytes);
// Check block.
assertNotNull(block);
block.verify();
assertEquals(BLOCK_NONCE, block.getNonce());
StoredBlock storedBlock = new StoredBlock(block, BigInteger.ONE, BLOCK_OF_INTEREST); // Nonsense work - not used in test.
// Create a wallet contain the miner's key that receives a spend from a coinbase.
ECKey miningKey = (new DumpedPrivateKey(params, MINING_PRIVATE_KEY)).getKey();
assertNotNull(miningKey);
Wallet wallet = new Wallet(params);
wallet.addKey(miningKey);
// Initial balance should be zero by construction.
assertEquals(BigInteger.ZERO, wallet.getBalance());
// Give the wallet the first transaction in the block - this is the coinbase tx.
List<Transaction> transactions = block.getTransactions();
assertNotNull(transactions);
wallet.receiveFromBlock(transactions.get(0), storedBlock, NewBlockType.BEST_CHAIN);
// Coinbase transaction should have been received successfully but be unavailable to spend (too young).
assertEquals(BALANCE_AFTER_BLOCK, wallet.getBalance(BalanceType.ESTIMATED));
assertEquals(BigInteger.ZERO, wallet.getBalance(BalanceType.AVAILABLE));
}
开发者ID:praus,项目名称:multicoinj,代码行数:38,代码来源:CoinbaseBlockTest.java
示例8: validateAmounts
import com.google.bitcoin.core.Wallet.BalanceType; //导入依赖的package包/类
private void validateAmounts(final boolean popups)
{
isValidAmounts = false;
final BigInteger amount = amountCalculatorLink.getAmount();
if (amount == null)
{
// empty amount
if (popups)
popupMessage(amountCalculatorLink.activeView(), getString(R.string.send_coins_fragment_amount_empty));
}
else if (amount.signum() > 0)
{
final BigInteger estimated = wallet.getBalance(BalanceType.ESTIMATED);
final BigInteger available = wallet.getBalance(BalanceType.AVAILABLE);
final BigInteger pending = estimated.subtract(available);
// TODO subscribe to wallet changes
final BigInteger availableAfterAmount = available.subtract(amount);
final boolean enoughFundsForAmount = availableAfterAmount.signum() >= 0;
if (enoughFundsForAmount)
{
// everything fine
isValidAmounts = true;
}
else
{
// not enough funds for amount
if (popups)
popupAvailable(amountCalculatorLink.activeView(), available, pending);
}
}
else
{
// invalid amount
if (popups)
popupMessage(amountCalculatorLink.activeView(), getString(R.string.send_coins_fragment_amount_error));
}
updateView();
}
开发者ID:9cat,项目名称:templecoin-android-wallet,代码行数:44,代码来源:SendCoinsFragment.java
示例9: handleGo
import com.google.bitcoin.core.Wallet.BalanceType; //导入依赖的package包/类
private void handleGo()
{
state = State.PREPARATION;
updateView();
// create spend
final BigInteger amount = amountCalculatorLink.getAmount();
final SendRequest sendRequest = SendRequest.to(validatedAddress.address, amount);
sendRequest.changeAddress = WalletUtils.pickOldestKey(wallet).toAddress(Constants.NETWORK_PARAMETERS);
sendRequest.emptyWallet = amount.equals(wallet.getBalance(BalanceType.AVAILABLE));
new SendCoinsOfflineTask(wallet, backgroundHandler)
{
@Override
protected void onSuccess(final Transaction transaction)
{
sentTransaction = transaction;
state = State.SENDING;
updateView();
sentTransaction.getConfidence().addEventListener(sentTransactionConfidenceListener);
if (bluetoothAdapter != null && bluetoothAdapter.isEnabled() && bluetoothMac != null && bluetoothEnableView.isChecked())
{
new SendBluetoothTask(bluetoothAdapter, backgroundHandler)
{
@Override
protected void onResult(final boolean ack)
{
bluetoothAck = ack;
if (state == State.SENDING)
state = State.SENT;
updateView();
}
}.send(bluetoothMac, transaction); // send asynchronously
}
application.broadcastTransaction(sentTransaction);
final Intent result = new Intent();
BitcoinIntegration.transactionHashToResult(result, sentTransaction.getHashAsString());
activity.setResult(Activity.RESULT_OK, result);
}
@Override
protected void onFailure()
{
state = State.FAILED;
updateView();
activity.longToast(R.string.send_coins_error_msg);
}
}.sendCoinsOffline(sendRequest); // send asynchronously
}
开发者ID:9cat,项目名称:templecoin-android-wallet,代码行数:58,代码来源:SendCoinsFragment.java
示例10: handleEmpty
import com.google.bitcoin.core.Wallet.BalanceType; //导入依赖的package包/类
private void handleEmpty()
{
final BigInteger available = wallet.getBalance(BalanceType.AVAILABLE);
amountCalculatorLink.setBtcAmount(available);
}
开发者ID:9cat,项目名称:templecoin-android-wallet,代码行数:7,代码来源:SendCoinsFragment.java
示例11: loadInBackground
import com.google.bitcoin.core.Wallet.BalanceType; //导入依赖的package包/类
@Override
public BigInteger loadInBackground()
{
return wallet.getBalance(BalanceType.ESTIMATED);
}
开发者ID:9cat,项目名称:templecoin-android-wallet,代码行数:6,代码来源:WalletBalanceLoader.java
示例12: updateFromModel
import com.google.bitcoin.core.Wallet.BalanceType; //导入依赖的package包/类
/**
* Update any UI elements from the model (hint that data has changed).
*/
public void updateFromModel(boolean blinkEnabled, boolean useBusyStatus) {
if (ColorAndFontConstants.isInverse()) {
inactiveBackGroundColor = new Color(Math.min(255, ColorAndFontConstants.BACKGROUND_COLOR.getRed() + 2 * COLOR_DELTA), Math.min(255,
ColorAndFontConstants.BACKGROUND_COLOR.getBlue() + 2 * COLOR_DELTA), Math.min(255, ColorAndFontConstants.BACKGROUND_COLOR.getGreen() + 2 * COLOR_DELTA));
} else {
inactiveBackGroundColor = new Color(Math.max(0, ColorAndFontConstants.BACKGROUND_COLOR.getRed() - COLOR_DELTA), Math.max(0,
ColorAndFontConstants.BACKGROUND_COLOR.getBlue() - COLOR_DELTA), Math.max(0, ColorAndFontConstants.BACKGROUND_COLOR.getGreen() - COLOR_DELTA));
}
BigInteger estimatedBalance = perWalletModelData.getWallet().getBalance(BalanceType.ESTIMATED);
String balanceTextToShowBTC = controller.getLocaliser().bitcoinValueToString(estimatedBalance, true, false);
String balanceTextToShowFiat = "";
if (CurrencyConverter.INSTANCE.getRate() != null && CurrencyConverter.INSTANCE.isShowingFiat()) {
Money fiat = CurrencyConverter.INSTANCE.convertFromBTCToFiat(estimatedBalance);
balanceTextToShowFiat = "(" + CurrencyConverter.INSTANCE.getFiatAsLocalisedString(fiat) + ")";
}
if (useBusyStatus && perWalletModelData.isBusy()) {
if (lastSyncPercent > 0) {
setSyncMessage(controller.getLocaliser().getString(perWalletModelData.getBusyTaskVerbKey()), lastSyncPercent);
} else {
setSyncMessage(controller.getLocaliser().getString(perWalletModelData.getBusyTaskVerbKey()), Message.NOT_RELEVANT_PERCENTAGE_COMPLETE);
}
} else {
if (amountLabelBTC != null && amountLabelBTC.getText() != null && !"".equals(amountLabelBTC.getText())
&& !balanceTextToShowBTC.equals(amountLabelBTC.getText()) && blinkEnabled) {
amountLabelBTC.blink(balanceTextToShowBTC);
amountLabelFiat.blink(balanceTextToShowFiat);
} else {
amountLabelBTC.setText(balanceTextToShowBTC);
amountLabelFiat.setText(balanceTextToShowFiat);
}
}
if (perWalletModelData.getWallet() != null) {
setIconForWalletType(perWalletModelData.getWallet().getEncryptionType(), walletTypeButton);
}
if (perWalletModelData.isFilesHaveBeenChangedByAnotherProcess()) {
myRoundedPanel.setOpaque(true);
myRoundedPanel.setBackground(ColorAndFontConstants.VERY_LIGHT_BACKGROUND_COLOR);
walletDescriptionTextField.setBackground(ColorAndFontConstants.VERY_LIGHT_BACKGROUND_COLOR);
walletDescriptionTextField.setText(controller.getLocaliser().getString("singleWalletPanel.dataHasChanged.text"));
walletDescriptionTextField.setForeground(ColorAndFontConstants.DATA_HAS_CHANGED_TEXT_COLOR);
walletDescriptionTextField.setDisabledTextColor(ColorAndFontConstants.DATA_HAS_CHANGED_TEXT_COLOR);
mainFrame.setUpdatesStoppedTooltip(walletDescriptionTextField);
walletDescriptionTextField.setEnabled(false);
walletDescriptionTextField.setEditable(false);
amountLabelBTC.setText("");
amountLabelBTC.setEnabled(false);
amountLabelFiat.setText("");
amountLabelFiat.setEnabled(false);
walletTypeButton.setEnabled(false);
}
invalidate();
revalidate();
repaint();
}
开发者ID:coinspark,项目名称:sparkbit,代码行数:64,代码来源:SingleWalletPanel.java
示例13: validateAmount
import com.google.bitcoin.core.Wallet.BalanceType; //导入依赖的package包/类
private boolean validateAmount(String amount) {
// Copy amount to wallet preferences.
validationState.put(VALIDATION_AMOUNT_VALUE, amount);
Boolean amountValidatesOk = Boolean.TRUE;
Boolean amountIsInvalid = Boolean.FALSE;
Boolean notEnoughFunds = Boolean.FALSE;
Boolean amountIsMissing = Boolean.FALSE;
Boolean amountIsNegativeOrZero = Boolean.FALSE;
Boolean amountIsTooSmall = Boolean.FALSE;
Boolean amountIsTooBigForMigration = Boolean.FALSE;
// See if the amount is missing.
if (amount == null || "".equals(amount) || amount.trim().length() == 0) {
amountIsMissing = Boolean.TRUE;
amountValidatesOk = Boolean.FALSE;
} else {
// See if the amount is a number.
BigInteger amountBigInteger = null;
try {
CurrencyConverterResult converterResult = CurrencyConverter.INSTANCE.parseToBTCNotLocalised(amount);
if (converterResult.isBtcMoneyValid()) {
// Parses ok.
amountBigInteger = converterResult.getBtcMoney().getAmount().toBigInteger();
} else {
amountIsInvalid = Boolean.TRUE;
amountValidatesOk = Boolean.FALSE;
}
} catch (NumberFormatException nfe) {
amountValidatesOk = Boolean.FALSE;
amountIsInvalid = Boolean.TRUE;
} catch (ArithmeticException ae) {
amountValidatesOk = Boolean.FALSE;
amountIsInvalid = Boolean.TRUE;
}
// See if the amount is negative or zero.
if (amountValidatesOk.booleanValue()) {
if (amountBigInteger.compareTo(BigInteger.ZERO) <= 0) {
amountValidatesOk = Boolean.FALSE;
amountIsNegativeOrZero = Boolean.TRUE;
} else {
if (amountBigInteger.compareTo(Transaction.MIN_NONDUST_OUTPUT) < 0) {
amountValidatesOk = Boolean.FALSE;
amountIsTooSmall = Boolean.TRUE;
} else {
// The fee is worked out in detail later, but we know it will be at least the minimum reference amount.
BigInteger totalSpend = amountBigInteger.add(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE);
BigInteger availableBalance = this.bitcoinController.getModel().getActiveWallet().getBalance(BalanceType.AVAILABLE);
BigInteger estimatedBalance = this.bitcoinController.getModel().getActiveWallet().getBalance(BalanceType.ESTIMATED);
log.debug("Amount = " + amountBigInteger.toString() + ", fee of at least " + Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.toString()
+ ", totalSpend = " + totalSpend.toString() + ", availableBalance = " + availableBalance.toString() + ", estimatedBalance = " + estimatedBalance.toString());
if (totalSpend.compareTo(availableBalance) > 0) {
// Not enough funds.
amountValidatesOk = Boolean.FALSE;
notEnoughFunds = Boolean.TRUE;
}
// Min balance for migration?
if (amountValidatesOk.booleanValue()) {
boolean b = CSMiscUtils.canSafelySpendWhileRespectingMigrationFee(this.bitcoinController, this.bitcoinController.getModel().getActiveWallet(), amountBigInteger);
if (!b) {
amountValidatesOk = Boolean.FALSE;
amountIsTooBigForMigration = Boolean.TRUE;
}
}
}
}
}
}
validationState.put(VALIDATION_AMOUNT_IS_MISSING, amountIsMissing.toString());
validationState.put(VALIDATION_AMOUNT_IS_NEGATIVE_OR_ZERO, amountIsNegativeOrZero.toString());
validationState.put(VALIDATION_AMOUNT_IS_TOO_SMALL, amountIsTooSmall.toString());
validationState.put(VALIDATION_AMOUNT_IS_INVALID, amountIsInvalid.toString());
validationState.put(VALIDATION_NOT_ENOUGH_FUNDS, notEnoughFunds.toString());
validationState.put(VALIDATION_AMOUNT_IS_TOO_BIG_FOR_MIGRATION, amountIsTooBigForMigration.toString());
return amountValidatesOk.booleanValue();
}
开发者ID:coinspark,项目名称:sparkbit,代码行数:81,代码来源:AssetValidator.java
示例14: coinbaseTransactionAvailability
import com.google.bitcoin.core.Wallet.BalanceType; //导入依赖的package包/类
@Test
public void coinbaseTransactionAvailability() throws Exception {
// Check that a coinbase transaction is only available to spend after NetworkParameters.getSpendableCoinbaseDepth() blocks.
// Create a second wallet to receive the coinbase spend.
Wallet wallet2 = new Wallet(unitTestParams);
ECKey receiveKey = new ECKey();
wallet2.addKey(receiveKey);
chain.addWallet(wallet2);
Address addressToSendTo = receiveKey.toAddress(unitTestParams);
// Create a block, sending the coinbase to the coinbaseTo address (which is in the wallet).
Block b1 = unitTestParams.getGenesisBlock().createNextBlockWithCoinbase(wallet.getKeys().get(0).getPubKey());
chain.add(b1);
// Check a transaction has been received.
assertNotNull(coinbaseTransaction);
// The coinbase tx is not yet available to spend.
assertEquals(BigInteger.ZERO, wallet.getBalance());
assertEquals(wallet.getBalance(BalanceType.ESTIMATED), Utils.toNanoCoins(50, 0));
assertTrue(!coinbaseTransaction.isMature());
// Attempt to spend the coinbase - this should fail as the coinbase is not mature yet.
Transaction coinbaseSpend = wallet.createSend(addressToSendTo, Utils.toNanoCoins(49, 0));
assertNull(coinbaseSpend);
// Check that the coinbase is unavailable to spend for the next spendableCoinbaseDepth - 2 blocks.
for (int i = 0; i < unitTestParams.getSpendableCoinbaseDepth() - 2; i++) {
// Non relevant tx - just for fake block creation.
Transaction tx2 = createFakeTx(unitTestParams, Utils.toNanoCoins(1, 0),
new ECKey().toAddress(unitTestParams));
Block b2 = createFakeBlock(blockStore, tx2).block;
chain.add(b2);
// Wallet still does not have the coinbase transaction available for spend.
assertEquals(BigInteger.ZERO, wallet.getBalance());
assertEquals(wallet.getBalance(BalanceType.ESTIMATED), Utils.toNanoCoins(50, 0));
// The coinbase transaction is still not mature.
assertTrue(!coinbaseTransaction.isMature());
// Attempt to spend the coinbase - this should fail.
coinbaseSpend = wallet.createSend(addressToSendTo, Utils.toNanoCoins(49, 0));
assertNull(coinbaseSpend);
}
// Give it one more block - should now be able to spend coinbase transaction. Non relevant tx.
Transaction tx3 = createFakeTx(unitTestParams, Utils.toNanoCoins(1, 0), new ECKey().toAddress(unitTestParams));
Block b3 = createFakeBlock(blockStore, tx3).block;
chain.add(b3);
// Wallet now has the coinbase transaction available for spend.
assertEquals(wallet.getBalance(), Utils.toNanoCoins(50, 0));
assertEquals(wallet.getBalance(BalanceType.ESTIMATED), Utils.toNanoCoins(50, 0));
assertTrue(coinbaseTransaction.isMature());
// Create a spend with the coinbase BTC to the address in the second wallet - this should now succeed.
Transaction coinbaseSend2 = wallet.createSend(addressToSendTo, Utils.toNanoCoins(49, 0));
assertNotNull(coinbaseSend2);
// Commit the coinbaseSpend to the first wallet and check the balances decrement.
wallet.commitTx(coinbaseSend2);
assertEquals(wallet.getBalance(BalanceType.ESTIMATED), Utils.toNanoCoins(1, 0));
// Available balance is zero as change has not been received from a block yet.
assertEquals(wallet.getBalance(BalanceType.AVAILABLE), Utils.toNanoCoins(0, 0));
// Give it one more block - change from coinbaseSpend should now be available in the first wallet.
Block b4 = createFakeBlock(blockStore, coinbaseSend2).block;
chain.add(b4);
assertEquals(wallet.getBalance(BalanceType.AVAILABLE), Utils.toNanoCoins(1, 0));
// Check the balances in the second wallet.
assertEquals(wallet2.getBalance(BalanceType.ESTIMATED), Utils.toNanoCoins(49, 0));
assertEquals(wallet2.getBalance(BalanceType.AVAILABLE), Utils.toNanoCoins(49, 0));
}
开发者ID:sserrano44,项目名称:bitcoinj-watcher-service,代码行数:79,代码来源:BlockChainTest.java
注:本文中的com.google.bitcoin.core.Wallet.BalanceType类示例整理自Github/MSDocs等源码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。 |
请发表评论