添加评分dialog,先设置为5分钟用于测试。

This commit is contained in:
ocean 2024-07-04 13:50:43 +08:00
parent 07bb4bf222
commit c268564445
16 changed files with 384 additions and 1 deletions

View File

@ -129,6 +129,7 @@ class App : Application() {
AnalysisUtil.logEvent(AnalysisUtil.USER_LAUNCH) AnalysisUtil.logEvent(AnalysisUtil.USER_LAUNCH)
app = this app = this
AppLifecycleHandler(this) AppLifecycleHandler(this)
saveInstallTimeIfNeeded()
initAd() initAd()
CommonIpInfoUtil.shared.initIPInfo() CommonIpInfoUtil.shared.initIPInfo()
UploadEventName.shared.init(this) UploadEventName.shared.init(this)
@ -155,4 +156,12 @@ class App : Application() {
LoLAds.setAdConfigKey("Music")//服务器端中⼴告json的key⻅⼴告配置json详情 LoLAds.setAdConfigKey("Music")//服务器端中⼴告json的key⻅⼴告配置json详情
LoLAds.setAdConfig(AppStore(this).adJson)//设置自定义广告配置json LoLAds.setAdConfig(AppStore(this).adJson)//设置自定义广告配置json
} }
private fun saveInstallTimeIfNeeded() {//用于弹出评分dialog的条件
val time = AppStore(this).showRateDialogTime
if (time == 0L) {//如果time为0L则表示安装或者是清除数据
val currentTime = System.currentTimeMillis()
AppStore(this).showRateDialogTime = currentTime
}
}
} }

View File

@ -1,5 +1,6 @@
package melody.offline.music.activity package melody.offline.music.activity
import android.annotation.SuppressLint
import android.content.Intent import android.content.Intent
import android.os.CountDownTimer import android.os.CountDownTimer
import android.os.Handler import android.os.Handler
@ -141,4 +142,9 @@ class LaunchActivity : MoBaseActivity() {
} }
}) })
} }
@SuppressLint("MissingSuperCall")
override fun onBackPressed() {
}
} }

View File

@ -66,7 +66,9 @@ import melody.offline.music.util.DownloadUtil
import melody.offline.music.util.FileSizeConverter import melody.offline.music.util.FileSizeConverter
import melody.offline.music.util.LogTag import melody.offline.music.util.LogTag
import melody.offline.music.view.MusicPlayerView import melody.offline.music.view.MusicPlayerView
import melody.offline.music.view.RatingDialog
import org.json.JSONObject import org.json.JSONObject
import java.util.concurrent.TimeUnit
@OptIn(UnstableApi::class) @OptIn(UnstableApi::class)
@ -507,4 +509,16 @@ abstract class MoBaseActivity : AppCompatActivity(), MusicPlayerView.PlaySkipFor
ContextCompat.getColor(this, R.color.main_bg_color) ContextCompat.getColor(this, R.color.main_bg_color)
bottomSheetDialog?.show() bottomSheetDialog?.show()
} }
fun showRatingDialog() {
val dialog = RatingDialog(this)
val installTime = appStore.showRateDialogTime
val currentTime = System.currentTimeMillis()
// 检测是否超过三天
if (currentTime - installTime > TimeUnit.DAYS.toMillis(3)) {
dialog.show()
//更新为当前时间
appStore.showRateDialogTime = System.currentTimeMillis()
}
}
} }

View File

@ -22,6 +22,7 @@ class PrimaryActivity : MoBaseActivity(), SearchFragment.SearchFragmentCancelCli
private val mFragments: MutableList<Fragment> = ArrayList() private val mFragments: MutableList<Fragment> = ArrayList()
private var currentIndex: Int = 0 private var currentIndex: Int = 0
private var mCurrentFragment: Fragment? = null private var mCurrentFragment: Fragment? = null
private var shouldShowDialog = false
fun getCurrentFragment(): Fragment? { fun getCurrentFragment(): Fragment? {
if (mCurrentFragment != null) { if (mCurrentFragment != null) {
@ -145,6 +146,19 @@ class PrimaryActivity : MoBaseActivity(), SearchFragment.SearchFragmentCancelCli
private fun activityOnResume() { private fun activityOnResume() {
addMusicPlayerViewToLayout(binding.playMusicLayout) addMusicPlayerViewToLayout(binding.playMusicLayout)
// 如果标志位为true则表示用户从其他页面返回到了首页
if (shouldShowDialog) {
// 检测并弹出Dialog
showRatingDialog()
// 重置标志位
shouldShowDialog = false
}
}
override fun onPause() {
super.onPause()
// 设置标志位为true表示用户离开了首页
shouldShowDialog = true
} }
override fun onFragmentClick() { override fun onFragmentClick() {

View File

@ -13,6 +13,7 @@ import melody.offline.music.util.openPrivacyPolicy
import melody.offline.music.util.openTermsOfService import melody.offline.music.util.openTermsOfService
import melody.offline.music.util.sendFeedback import melody.offline.music.util.sendFeedback
import melody.offline.music.util.shareApp import melody.offline.music.util.shareApp
import melody.offline.music.view.RatingDialog
class SettingsActivity : AppCompatActivity() { class SettingsActivity : AppCompatActivity() {
@ -62,6 +63,10 @@ class SettingsActivity : AppCompatActivity() {
binding.tosBtn.setOnClickListener { binding.tosBtn.setOnClickListener {
openTermsOfService(this, TERMS_OF_SERVICE_URL) openTermsOfService(this, TERMS_OF_SERVICE_URL)
} }
binding.rateUsBtn.setOnClickListener {
val dialog = RatingDialog(this)
dialog.show()
}
} }
} }

View File

@ -59,6 +59,12 @@ class AppStore(context: Context) {
defaultValue = Constants.DEFAULT_SHOW_AD_INTERVAL_TIME defaultValue = Constants.DEFAULT_SHOW_AD_INTERVAL_TIME
) )
//记录弹出dialog的时间
var showRateDialogTime: Long by store.long(
key = SHOW_RATE_DIALOG_TIME,
defaultValue = 0L
)
companion object { companion object {
private const val FILE_NAME = "music_oo_app" private const val FILE_NAME = "music_oo_app"
const val SEARCH_HISTORY = "search_history" const val SEARCH_HISTORY = "search_history"
@ -69,6 +75,6 @@ class AppStore(context: Context) {
const val IP_COUNTRY_CODE = "ip_country_code" const val IP_COUNTRY_CODE = "ip_country_code"
const val FIRST_OPEN_IS_SUCCEED = "first_open_is_succeed" const val FIRST_OPEN_IS_SUCCEED = "first_open_is_succeed"
const val SHOULD_ENTER_MUSIC_PAGE = "key_should_enter_music_page" const val SHOULD_ENTER_MUSIC_PAGE = "key_should_enter_music_page"
const val SHOW_RATE_DIALOG_TIME = "show_rate_dialog_time"
} }
} }

View File

@ -34,6 +34,9 @@ object AnalysisUtil {
const val SEARCH_RESULT_PV = "search_result_pv"//搜索结果曝光 const val SEARCH_RESULT_PV = "search_result_pv"//搜索结果曝光
const val SEARCH_RESULT_SUCCESS_ACTION = "search_result_success_action"//搜索有结果 const val SEARCH_RESULT_SUCCESS_ACTION = "search_result_success_action"//搜索有结果
const val SEARCH_TRIGGER = "search_trigger "//触发搜索 const val SEARCH_TRIGGER = "search_trigger "//触发搜索
const val RATING_DIALOG_SHOW = "rating_dialog_show"
const val RATING_DIALOG_OK_CLICK = "rating_dialog_ok_click"
const val RATING_DIALOG_CANCEL_CLICK = "rating_dialog_cancel_click"
private const val AD_INST_SPLASH_SUCCESS = "ad_user_open_success"//首页开屏广告展示成功 private const val AD_INST_SPLASH_SUCCESS = "ad_user_open_success"//首页开屏广告展示成功

View File

@ -1,9 +1,11 @@
package melody.offline.music.util package melody.offline.music.util
import android.content.ActivityNotFoundException
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.widget.Toast import android.widget.Toast
import androidx.core.content.ContextCompat.startActivity
const val PRIVACY_POLICY_URL = "https://himelody.mystrikingly.com/privacy" const val PRIVACY_POLICY_URL = "https://himelody.mystrikingly.com/privacy"
const val TERMS_OF_SERVICE_URL = "https://himelody.mystrikingly.com/terms" const val TERMS_OF_SERVICE_URL = "https://himelody.mystrikingly.com/terms"
@ -41,3 +43,13 @@ fun sendFeedback(context: Context, email: String, subject: String) {
Toast.makeText(context,"There is no app that supports sending emails",Toast.LENGTH_LONG).show() Toast.makeText(context,"There is no app that supports sending emails",Toast.LENGTH_LONG).show()
} }
} }
fun openGooglePlay(context: Context, packageName: String) {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=$packageName"))
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
try {
context.startActivity(intent)
} catch (e: ActivityNotFoundException) {
e.printStackTrace()
}
}

View File

@ -0,0 +1,73 @@
package melody.offline.music.view
import android.app.Dialog
import android.content.Context
import android.view.LayoutInflater
import melody.offline.music.R
import melody.offline.music.databinding.DialogRatingBinding
import melody.offline.music.util.AnalysisUtil
import melody.offline.music.util.openGooglePlay
import melody.offline.music.util.sendFeedback
class RatingDialog(private val mContext: Context) : Dialog(mContext) {
private var starType = 5
private var binding: DialogRatingBinding =
DialogRatingBinding.inflate(LayoutInflater.from(mContext))
init {
setContentView(binding.root)
window?.setBackgroundDrawableResource(android.R.color.transparent)
setCanceledOnTouchOutside(false)
initClick()
}
private fun initClick() {
binding.dialogOkBtn.setOnClickListener {
when (starType) {
1, 2, 3 -> {
sendFeedback(
mContext,
"motaleb3024@gmail.com",
mContext.getString(R.string.app_name)
)
}
4, 5 -> {
openGooglePlay(mContext, mContext.packageName)
}
}
dismiss()
AnalysisUtil
}
binding.dialogCancelBtn.setOnClickListener {
dismiss()
}
val stars =
arrayOf(binding.star1, binding.star2, binding.star3, binding.star4, binding.star5)
stars.forEachIndexed { index, imageView ->
//由于数组索引从0开始而星星的评分从1开始因此需要将index加1
imageView.setOnClickListener {
starType = index + 1
updateStarUi(starType)
}
}
}
private fun updateStarUi(type: Int) {
val stars = arrayOf(
binding.star1Img,
binding.star2Img,
binding.star3Img,
binding.star4Img,
binding.star5Img
)
stars.forEachIndexed { index, imageView ->
//当前索引是否小于type如果是则表示该星星需要被选中否则表示该星星未被选中。
val resource =
if (index < type) R.drawable.star_select_icon else R.drawable.star_unselect_icon
imageView.setImageResource(resource)
}
}
}

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/bottom_layout_bg_color" />
<corners android:radius="18dp"/>
</shape>

View File

@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<group>
<clip-path
android:pathData="M0,0h24v24h-24z"/>
<path
android:pathData="M18.308,14.438C18.579,15.697 18.818,16.837 19.025,17.857C19.121,18.287 19.208,18.717 19.288,19.147C19.368,19.578 19.444,19.968 19.515,20.319C19.587,20.669 19.647,20.968 19.695,21.215C19.742,21.462 19.774,21.618 19.79,21.681C19.838,22 19.766,22.211 19.575,22.315C19.384,22.418 19.169,22.47 18.93,22.47C18.85,22.47 18.734,22.442 18.583,22.386C18.432,22.331 18.316,22.287 18.236,22.255L11.997,18.622C10.866,19.291 9.838,19.888 8.914,20.414C8.515,20.638 8.121,20.861 7.73,21.084C7.34,21.307 6.985,21.514 6.667,21.705C6.348,21.896 6.073,22.056 5.842,22.183C5.611,22.311 5.456,22.39 5.376,22.422C5.217,22.502 5.053,22.53 4.886,22.506C4.719,22.482 4.567,22.422 4.432,22.327C4.296,22.231 4.197,22.115 4.133,21.98C4.069,21.845 4.053,21.705 4.085,21.562C4.101,21.498 4.141,21.343 4.205,21.096C4.268,20.849 4.34,20.554 4.42,20.211C4.499,19.868 4.591,19.49 4.695,19.076C4.798,18.661 4.906,18.239 5.017,17.809C5.256,16.821 5.527,15.705 5.83,14.462C4.89,13.649 4.045,12.924 3.296,12.287C2.977,12.016 2.663,11.749 2.352,11.486C2.041,11.223 1.762,10.984 1.515,10.769C1.268,10.554 1.065,10.378 0.906,10.243C0.746,10.108 0.659,10.032 0.643,10.016C0.452,9.841 0.288,9.645 0.153,9.43C0.017,9.215 -0.034,8.996 -0.003,8.773C0.029,8.55 0.117,8.375 0.26,8.247C0.404,8.12 0.563,8.04 0.738,8.008L8.125,7.339L10.874,0.932C10.969,0.677 11.105,0.458 11.28,0.275C11.456,0.092 11.695,0 11.997,0C12.157,0 12.296,0.036 12.416,0.108C12.535,0.179 12.635,0.263 12.715,0.359C12.794,0.454 12.862,0.55 12.918,0.645C12.974,0.741 13.017,0.821 13.049,0.884L15.726,7.291L23.113,7.984C23.432,8.064 23.655,8.159 23.782,8.271C23.91,8.382 23.973,8.558 23.973,8.797C23.973,9.02 23.906,9.215 23.77,9.382C23.635,9.55 23.463,9.753 23.256,9.992L18.308,14.438Z"
android:fillColor="#FECA5A"/>
</group>
</vector>

View File

@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<group>
<clip-path
android:pathData="M0,0h24v24h-24z"/>
<path
android:strokeWidth="1"
android:pathData="M17.974,14.066L17.758,14.26L17.819,14.543C18.09,15.801 18.329,16.938 18.535,17.956L18.535,17.956L18.537,17.965C18.632,18.39 18.718,18.814 18.797,19.239C18.877,19.671 18.953,20.065 19.025,20.419C19.097,20.768 19.156,21.065 19.204,21.31C19.246,21.527 19.278,21.687 19.298,21.775C19.304,21.819 19.305,21.853 19.304,21.878C19.304,21.883 19.304,21.888 19.303,21.892C19.201,21.941 19.081,21.969 18.935,21.97C18.932,21.97 18.921,21.968 18.901,21.963C18.867,21.955 18.819,21.941 18.756,21.917C18.627,21.87 18.528,21.832 18.455,21.804L12.249,18.189L11.995,18.042L11.743,18.191C10.614,18.859 9.589,19.455 8.668,19.979C8.269,20.202 7.874,20.426 7.482,20.649C7.089,20.874 6.732,21.083 6.409,21.276C6.094,21.466 5.825,21.622 5.6,21.746C5.364,21.876 5.236,21.94 5.19,21.958L5.171,21.966L5.152,21.975C5.079,22.012 5.018,22.02 4.957,22.011C4.866,21.998 4.789,21.967 4.72,21.918C4.647,21.867 4.608,21.816 4.585,21.767C4.569,21.732 4.566,21.706 4.572,21.675C4.589,21.609 4.627,21.458 4.689,21.221C4.754,20.969 4.826,20.67 4.907,20.324C4.986,19.985 5.077,19.609 5.18,19.197C5.283,18.784 5.39,18.363 5.501,17.934L5.501,17.934L5.503,17.926C5.742,16.939 6.013,15.823 6.316,14.58L6.388,14.284L6.157,14.084C5.216,13.271 4.37,12.545 3.62,11.906L3.62,11.906C3.301,11.635 2.986,11.368 2.675,11.104C2.366,10.843 2.089,10.605 1.844,10.392C1.596,10.176 1.391,9.999 1.23,9.862C1.15,9.795 1.09,9.743 1.047,9.706C1.026,9.688 1.01,9.674 0.999,9.665C0.995,9.661 0.993,9.658 0.991,9.657L0.989,9.655L0.981,9.647C0.822,9.502 0.687,9.341 0.576,9.164C0.495,9.035 0.479,8.934 0.492,8.844C0.511,8.716 0.552,8.656 0.593,8.621C0.667,8.555 0.738,8.52 0.81,8.504L8.17,7.837L8.467,7.81L8.584,7.536L11.333,1.129L11.338,1.119L11.342,1.108C11.416,0.911 11.516,0.751 11.642,0.621C11.705,0.555 11.802,0.5 11.997,0.5C12.079,0.5 12.127,0.518 12.158,0.536C12.236,0.583 12.291,0.631 12.33,0.679C12.394,0.756 12.446,0.828 12.486,0.897C12.534,0.98 12.57,1.045 12.595,1.094L15.265,7.484L15.381,7.761L15.68,7.789L23.027,8.478C23.297,8.549 23.415,8.615 23.451,8.645C23.452,8.647 23.454,8.651 23.456,8.657C23.463,8.677 23.473,8.72 23.473,8.797C23.473,8.91 23.442,8.993 23.382,9.068C23.255,9.224 23.095,9.415 22.899,9.641L17.974,14.066Z"
android:strokeAlpha="0.4"
android:fillColor="#00000000"
android:strokeColor="#ffffff"/>
</group>
</vector>

View File

@ -108,6 +108,33 @@
android:src="@drawable/back_icon" /> android:src="@drawable/back_icon" />
</LinearLayout> </LinearLayout>
<LinearLayout
android:id="@+id/rate_us_btn"
android:layout_width="match_parent"
android:layout_height="56dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingEnd="16dp">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:fontFamily="@font/medium_font"
android:gravity="center_vertical"
android:text="@string/rate_us"
android:textColor="@color/white"
android:textSize="16dp" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:rotation="180"
android:src="@drawable/back_icon" />
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/share_btn" android:id="@+id/share_btn"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -0,0 +1,173 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="70dp"
android:background="@drawable/drw_rating_dialog_bg"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="90dp"
android:layout_marginEnd="20dp"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/medium_font"
android:text="@string/five_star_rating"
android:textColor="@color/white"
android:textSize="20dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:fontFamily="@font/regular_font"
android:gravity="start"
android:text="@string/rating_content"
android:textColor="@color/white"
android:textSize="14dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/star1"
android:layout_width="40dp"
android:layout_height="40dp"
android:gravity="center">
<ImageView
android:id="@+id/star1_img"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/star_select_icon" />
</LinearLayout>
<LinearLayout
android:id="@+id/star2"
android:layout_width="40dp"
android:layout_height="40dp"
android:gravity="center">
<ImageView
android:id="@+id/star2_img"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/star_select_icon" />
</LinearLayout>
<LinearLayout
android:id="@+id/star3"
android:layout_width="40dp"
android:layout_height="40dp"
android:gravity="center">
<ImageView
android:id="@+id/star3_img"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/star_select_icon" />
</LinearLayout>
<LinearLayout
android:id="@+id/star4"
android:layout_width="40dp"
android:layout_height="40dp"
android:gravity="center">
<ImageView
android:id="@+id/star4_img"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/star_select_icon" />
</LinearLayout>
<LinearLayout
android:id="@+id/star5"
android:layout_width="40dp"
android:layout_height="40dp"
android:gravity="center">
<ImageView
android:id="@+id/star5_img"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/star_select_icon" />
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="24dp"
android:background="@color/liner_color" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/dialog_cancel_btn"
android:layout_width="0dp"
android:layout_height="56dp"
android:layout_weight="1"
android:fontFamily="@font/regular_font"
android:gravity="center"
android:text="@string/cancel"
android:textColor="@color/white_60"
android:textSize="16dp" />
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="@color/liner_color" />
<TextView
android:id="@+id/dialog_ok_btn"
android:layout_width="0dp"
android:layout_height="56dp"
android:layout_weight="1"
android:fontFamily="@font/medium_font"
android:gravity="center"
android:text="@string/rate_the_app"
android:textColor="@color/green"
android:textSize="16dp" />
</LinearLayout>
</LinearLayout>
<ImageView
android:layout_width="184dp"
android:layout_height="140dp"
android:layout_centerHorizontal="true"
android:src="@mipmap/rating_img" />
</RelativeLayout>
</LinearLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -14,6 +14,7 @@
<string name="search">Search</string> <string name="search">Search</string>
<string name="about">About</string> <string name="about">About</string>
<string name="feedback">Feedback</string> <string name="feedback">Feedback</string>
<string name="rate_us">Rate Us</string>
<string name="share">Share</string> <string name="share">Share</string>
<string name="privacy_policy">Privacy Policy</string> <string name="privacy_policy">Privacy Policy</string>
<string name="terms_of_service">Terms of Service</string> <string name="terms_of_service">Terms of Service</string>
@ -54,4 +55,7 @@
<string name="created_successfully">Created successfully</string> <string name="created_successfully">Created successfully</string>
<string name="song_exists_playlist_hint">This song already exists in this playlist.</string> <string name="song_exists_playlist_hint">This song already exists in this playlist.</string>
<string name="added_playlist_success_Hint">Successfully added to the playlist</string> <string name="added_playlist_success_Hint">Successfully added to the playlist</string>
<string name="rating_content">Thank you for using our app. If you enjoy our service, please give us a five-star rating. Your feedback is very important to us!</string>
<string name="five_star_rating">Five-Star Rating</string>
<string name="rate_the_app">Rate the app</string>
</resources> </resources>