注册邀请码
This commit is contained in:
parent
ddd50a65dc
commit
24c4a4b70c
@ -85,13 +85,14 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("androidx.multidex:multidex:2.0.1")
|
implementation("androidx.multidex:multidex:2.0.1")
|
||||||
// implementation(platform("com.google.firebase:firebase-bom:34.0.0"))
|
implementation("com.android.installreferrer:installreferrer:2.2")
|
||||||
// implementation("com.google.firebase:firebase-auth")
|
// implementation(platform("com.google.firebase:firebase-bom:34.0.0"))
|
||||||
// implementation("com.google.firebase:firebase-core:16.0.8")
|
// implementation("com.google.firebase:firebase-auth")
|
||||||
// implementation("com.google.android.gms:play-services-auth:21.1.1")
|
// implementation("com.google.firebase:firebase-core:16.0.8")
|
||||||
}
|
// implementation("com.google.android.gms:play-services-auth:21.1.1")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
flutter {
|
flutter {
|
||||||
|
|||||||
@ -1,10 +1,83 @@
|
|||||||
package com.org.yumiparty
|
package com.org.yumiparty
|
||||||
|
|
||||||
|
import com.android.installreferrer.api.InstallReferrerClient
|
||||||
|
import com.android.installreferrer.api.InstallReferrerStateListener
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
import io.flutter.embedding.engine.FlutterEngine
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
|
import io.flutter.plugin.common.MethodChannel
|
||||||
|
|
||||||
class MainActivity : FlutterActivity() {
|
class MainActivity : FlutterActivity() {
|
||||||
|
private var installReferrerClient: InstallReferrerClient? = null
|
||||||
|
|
||||||
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||||
super.configureFlutterEngine(flutterEngine) // 这行必须存在!
|
super.configureFlutterEngine(flutterEngine) // 这行必须存在!
|
||||||
|
MethodChannel(
|
||||||
|
flutterEngine.dartExecutor.binaryMessenger,
|
||||||
|
INSTALL_REFERRER_CHANNEL
|
||||||
|
).setMethodCallHandler { call, result ->
|
||||||
|
when (call.method) {
|
||||||
|
"getInstallReferrer" -> getInstallReferrer(result)
|
||||||
|
else -> result.notImplemented()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
installReferrerClient?.endConnection()
|
||||||
|
installReferrerClient = null
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getInstallReferrer(result: MethodChannel.Result) {
|
||||||
|
val client = InstallReferrerClient.newBuilder(this).build()
|
||||||
|
installReferrerClient = client
|
||||||
|
var hasResponded = false
|
||||||
|
|
||||||
|
fun respondOnce(value: String?) {
|
||||||
|
if (hasResponded) return
|
||||||
|
hasResponded = true
|
||||||
|
result.success(value)
|
||||||
|
client.endConnection()
|
||||||
|
if (installReferrerClient === client) {
|
||||||
|
installReferrerClient = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun respondError(errorCode: String, message: String?) {
|
||||||
|
if (hasResponded) return
|
||||||
|
hasResponded = true
|
||||||
|
result.error(errorCode, message, null)
|
||||||
|
client.endConnection()
|
||||||
|
if (installReferrerClient === client) {
|
||||||
|
installReferrerClient = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
client.startConnection(object : InstallReferrerStateListener {
|
||||||
|
override fun onInstallReferrerSetupFinished(responseCode: Int) {
|
||||||
|
when (responseCode) {
|
||||||
|
InstallReferrerClient.InstallReferrerResponse.OK -> {
|
||||||
|
try {
|
||||||
|
respondOnce(client.installReferrer.installReferrer)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
respondError("INSTALL_REFERRER_ERROR", e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> respondOnce(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onInstallReferrerServiceDisconnected() {
|
||||||
|
respondOnce(null)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (e: Exception) {
|
||||||
|
respondError("INSTALL_REFERRER_CONNECTION_ERROR", e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val INSTALL_REFERRER_CHANNEL = "com.org.yumiparty/install_referrer"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,6 @@
|
|||||||
"profilePhoto": "صورة الملف الشخصي",
|
"profilePhoto": "صورة الملف الشخصي",
|
||||||
"noHistoricalRecordsAvailable": "لا توجد سجلات تاريخية متاحة.",
|
"noHistoricalRecordsAvailable": "لا توجد سجلات تاريخية متاحة.",
|
||||||
"inviteNewUsersToEarnCoins": "ادعُ مستخدمين جدد لكسب العملات",
|
"inviteNewUsersToEarnCoins": "ادعُ مستخدمين جدد لكسب العملات",
|
||||||
"inviteActivity": "نشاط الدعوة",
|
|
||||||
"crateMyRoom": "أنشئ غرفتك الخاصة.",
|
"crateMyRoom": "أنشئ غرفتك الخاصة.",
|
||||||
"casualInteraction": "التفاعل العفوي",
|
"casualInteraction": "التفاعل العفوي",
|
||||||
"haveGamePlayingTips": "لديك لعبة جارية، يرجى الخروج من اللعبة الحالية أولاً، هل أنت متأكد من الخروج؟",
|
"haveGamePlayingTips": "لديك لعبة جارية، يرجى الخروج من اللعبة الحالية أولاً، هل أنت متأكد من الخروج؟",
|
||||||
|
|||||||
@ -32,7 +32,6 @@
|
|||||||
"aboutMe": "আমার সম্পর্কে",
|
"aboutMe": "আমার সম্পর্কে",
|
||||||
"noHistoricalRecordsAvailable": "কোনও ঐতিহাসিক রেকর্ড পাওয়া যায়নি।",
|
"noHistoricalRecordsAvailable": "কোনও ঐতিহাসিক রেকর্ড পাওয়া যায়নি।",
|
||||||
"inviteNewUsersToEarnCoins": "নতুন ব্যবহারকারীকে আমন্ত্রণ করুন কয়েন উপার্জনের জন্য",
|
"inviteNewUsersToEarnCoins": "নতুন ব্যবহারকারীকে আমন্ত্রণ করুন কয়েন উপার্জনের জন্য",
|
||||||
"inviteActivity": "আমন্ত্রণ কার্যক্রম",
|
|
||||||
"crateMyRoom": "নিজের রুম তৈরি করুন।",
|
"crateMyRoom": "নিজের রুম তৈরি করুন।",
|
||||||
"myRoom": "আমার রুম",
|
"myRoom": "আমার রুম",
|
||||||
"recent": "সাম্প্রতিক",
|
"recent": "সাম্প্রতিক",
|
||||||
|
|||||||
@ -33,7 +33,6 @@
|
|||||||
"myRoom": "My room",
|
"myRoom": "My room",
|
||||||
"noHistoricalRecordsAvailable": "No historical records available.",
|
"noHistoricalRecordsAvailable": "No historical records available.",
|
||||||
"inviteNewUsersToEarnCoins": "Invite new users to earn coins",
|
"inviteNewUsersToEarnCoins": "Invite new users to earn coins",
|
||||||
"inviteActivity": "Invite Activity",
|
|
||||||
"crateMyRoom": "CREATE YOUR OWN ROOM.",
|
"crateMyRoom": "CREATE YOUR OWN ROOM.",
|
||||||
"casualInteraction": "Casual Interaction",
|
"casualInteraction": "Casual Interaction",
|
||||||
"haveGamePlayingTips": "You have a game in progress. Please exit the current game. Are you sure you want to exit?",
|
"haveGamePlayingTips": "You have a game in progress. Please exit the current game. Are you sure you want to exit?",
|
||||||
|
|||||||
@ -31,7 +31,6 @@
|
|||||||
"roomPassword": "Oda Şifresi",
|
"roomPassword": "Oda Şifresi",
|
||||||
"noHistoricalRecordsAvailable": "Geçmiş kayıt bulunamadı.",
|
"noHistoricalRecordsAvailable": "Geçmiş kayıt bulunamadı.",
|
||||||
"inviteNewUsersToEarnCoins": "Yeni kullanıcıları davet ederek coin kazanın",
|
"inviteNewUsersToEarnCoins": "Yeni kullanıcıları davet ederek coin kazanın",
|
||||||
"inviteActivity": "Davet Etkinliği",
|
|
||||||
"crateMyRoom": "KENDİ ODANIZI OLUŞTURUN.",
|
"crateMyRoom": "KENDİ ODANIZI OLUŞTURUN.",
|
||||||
"event": "Etkinlik",
|
"event": "Etkinlik",
|
||||||
"clearCacheSuccessfully": "Önbellek başarıyla temizlendi",
|
"clearCacheSuccessfully": "Önbellek başarıyla temizlendi",
|
||||||
|
|||||||
@ -502,7 +502,7 @@
|
|||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 5;
|
CURRENT_PROJECT_VERSION = 6;
|
||||||
DEVELOPMENT_TEAM = S9X2AJ2US9;
|
DEVELOPMENT_TEAM = S9X2AJ2US9;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
@ -511,7 +511,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.2.1;
|
MARKETING_VERSION = 1.2.2;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.org.yumiparty;
|
PRODUCT_BUNDLE_IDENTIFIER = com.org.yumiparty;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
@ -693,7 +693,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = Runner/RunnerDebug.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/RunnerDebug.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 5;
|
CURRENT_PROJECT_VERSION = 6;
|
||||||
DEVELOPMENT_TEAM = F33K8VUZ62;
|
DEVELOPMENT_TEAM = F33K8VUZ62;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
@ -702,7 +702,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.2.1;
|
MARKETING_VERSION = 1.2.2;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.org.yumiparty;
|
PRODUCT_BUNDLE_IDENTIFIER = com.org.yumiparty;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
@ -722,7 +722,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = Runner/RunnerRelease.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/RunnerRelease.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 5;
|
CURRENT_PROJECT_VERSION = 6;
|
||||||
DEVELOPMENT_TEAM = F33K8VUZ62;
|
DEVELOPMENT_TEAM = F33K8VUZ62;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
@ -731,7 +731,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.2.1;
|
MARKETING_VERSION = 1.2.2;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.org.yumiparty;
|
PRODUCT_BUNDLE_IDENTIFIER = com.org.yumiparty;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
|||||||
@ -73,11 +73,6 @@ class SCAppLocalizations {
|
|||||||
String get inviteNewUsersToEarnCoins =>
|
String get inviteNewUsersToEarnCoins =>
|
||||||
translate('inviteNewUsersToEarnCoins');
|
translate('inviteNewUsersToEarnCoins');
|
||||||
|
|
||||||
String get inviteActivity {
|
|
||||||
final value = translate('inviteActivity');
|
|
||||||
return value == 'inviteActivity' ? 'Invite Activity' : value;
|
|
||||||
}
|
|
||||||
|
|
||||||
String get avoidBeingKicked => translate('avoidBeingKicked');
|
String get avoidBeingKicked => translate('avoidBeingKicked');
|
||||||
|
|
||||||
String get vipEntranceEffect => translate('vipEntranceEffect');
|
String get vipEntranceEffect => translate('vipEntranceEffect');
|
||||||
|
|||||||
@ -23,6 +23,7 @@ import 'package:yumi/services/auth/user_profile_manager.dart';
|
|||||||
import 'package:yumi/services/audio/rtc_manager.dart';
|
import 'package:yumi/services/audio/rtc_manager.dart';
|
||||||
import 'package:yumi/services/audio/rtm_manager.dart';
|
import 'package:yumi/services/audio/rtm_manager.dart';
|
||||||
import 'package:yumi/app/constants/sc_global_config.dart';
|
import 'package:yumi/app/constants/sc_global_config.dart';
|
||||||
|
import 'package:yumi/shared/tools/sc_install_referrer_utils.dart';
|
||||||
|
|
||||||
import '../../../shared/business_logic/usecases/sc_custom_filtering_textinput_formatter.dart';
|
import '../../../shared/business_logic/usecases/sc_custom_filtering_textinput_formatter.dart';
|
||||||
import '../../country/country_route.dart';
|
import '../../country/country_route.dart';
|
||||||
@ -53,6 +54,7 @@ class _SCEditProfilePageState extends State<SCEditProfilePage> {
|
|||||||
);
|
);
|
||||||
Provider.of<SCAppGeneralManager>(context, listen: false).selectCountryInfo =
|
Provider.of<SCAppGeneralManager>(context, listen: false).selectCountryInfo =
|
||||||
null;
|
null;
|
||||||
|
_fillInvitationCodeFromInstallReferrer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -529,6 +531,22 @@ class _SCEditProfilePageState extends State<SCEditProfilePage> {
|
|||||||
return eighteenYearsAgo;
|
return eighteenYearsAgo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _fillInvitationCodeFromInstallReferrer() async {
|
||||||
|
final inviteCode = await SCInstallReferrerUtils.getInviteCode();
|
||||||
|
if (!mounted ||
|
||||||
|
inviteCode.isEmpty ||
|
||||||
|
invitationCodeController.text.trim().isNotEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final normalizedInviteCode =
|
||||||
|
inviteCode.length > 10 ? inviteCode.substring(0, 10) : inviteCode;
|
||||||
|
invitationCodeController.value = TextEditingValue(
|
||||||
|
text: normalizedInviteCode,
|
||||||
|
selection: TextSelection.collapsed(offset: normalizedInviteCode.length),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
String? _preferNonEmpty(String? primary, String? fallback) {
|
String? _preferNonEmpty(String? primary, String? fallback) {
|
||||||
if (primary != null && primary.isNotEmpty) {
|
if (primary != null && primary.isNotEmpty) {
|
||||||
return primary;
|
return primary;
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import 'package:yumi/shared/data_sources/sources/repositories/sc_user_repository
|
|||||||
import 'package:yumi/ui_kit/components/sc_compontent.dart';
|
import 'package:yumi/ui_kit/components/sc_compontent.dart';
|
||||||
import 'package:yumi/ui_kit/components/sc_debounce_widget.dart';
|
import 'package:yumi/ui_kit/components/sc_debounce_widget.dart';
|
||||||
import 'package:yumi/ui_kit/widgets/id/sc_special_id_badge.dart';
|
import 'package:yumi/ui_kit/widgets/id/sc_special_id_badge.dart';
|
||||||
|
import 'package:yumi/ui_kit/widgets/svga/sc_svga_asset_widget.dart';
|
||||||
|
|
||||||
class MePage2 extends StatefulWidget {
|
class MePage2 extends StatefulWidget {
|
||||||
const MePage2({super.key});
|
const MePage2({super.key});
|
||||||
@ -26,6 +27,7 @@ class MePage2 extends StatefulWidget {
|
|||||||
class _MePage2State extends State<MePage2> {
|
class _MePage2State extends State<MePage2> {
|
||||||
static const String _inviteActivityUrl =
|
static const String _inviteActivityUrl =
|
||||||
'https://h5.haiyihy.com/app-invite/index.html';
|
'https://h5.haiyihy.com/app-invite/index.html';
|
||||||
|
static const double _inviteActivityHorizontalScale = 750 / 662;
|
||||||
|
|
||||||
Map<String, SCUserCounterRes> _counterMap = {};
|
Map<String, SCUserCounterRes> _counterMap = {};
|
||||||
|
|
||||||
@ -105,7 +107,7 @@ class _MePage2State extends State<MePage2> {
|
|||||||
_buildEntryRow(),
|
_buildEntryRow(),
|
||||||
SizedBox(height: 12.w),
|
SizedBox(height: 12.w),
|
||||||
_buildWalletCard(),
|
_buildWalletCard(),
|
||||||
SizedBox(height: 12.w),
|
_buildInviteActivityBanner(),
|
||||||
_buildMenuCard2(),
|
_buildMenuCard2(),
|
||||||
SizedBox(height: 12.w),
|
SizedBox(height: 12.w),
|
||||||
_buildMenuCard([
|
_buildMenuCard([
|
||||||
@ -320,6 +322,66 @@ class _MePage2State extends State<MePage2> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildInviteActivityBanner() {
|
||||||
|
return SCDebounceWidget(
|
||||||
|
onTap: _openInviteActivity,
|
||||||
|
child: LayoutBuilder(
|
||||||
|
builder: (context, constraints) {
|
||||||
|
final width =
|
||||||
|
constraints.maxWidth.isFinite
|
||||||
|
? constraints.maxWidth
|
||||||
|
: ScreenUtil().screenWidth - 20.w;
|
||||||
|
final height = width / 5;
|
||||||
|
|
||||||
|
return SizedBox(
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
child: Stack(
|
||||||
|
clipBehavior: Clip.none,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: [
|
||||||
|
Positioned.fill(
|
||||||
|
child: Transform(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
transform: Matrix4.diagonal3Values(
|
||||||
|
_inviteActivityHorizontalScale,
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
),
|
||||||
|
child: SCSvgaAssetWidget(
|
||||||
|
assetPath: _inviteActivitySvgaAsset,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
active: true,
|
||||||
|
loop: true,
|
||||||
|
fit: BoxFit.fill,
|
||||||
|
allowDrawingOverflow: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String get _inviteActivitySvgaAsset {
|
||||||
|
switch (SCGlobalConfig.lang) {
|
||||||
|
case 'ar':
|
||||||
|
return 'sc_images/index/sc_invite_activity_rtl.svga';
|
||||||
|
case 'bn':
|
||||||
|
case 'fa':
|
||||||
|
return 'sc_images/index/sc_invite_activity_fa.svga';
|
||||||
|
case 'tr':
|
||||||
|
case 'pt':
|
||||||
|
return 'sc_images/index/sc_invite_activity_pt.svga';
|
||||||
|
default:
|
||||||
|
return 'sc_images/index/sc_invite_activity.svga';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildMenuCard2() {
|
Widget _buildMenuCard2() {
|
||||||
final userProfile = context.watch<SocialChatUserProfileManager>();
|
final userProfile = context.watch<SocialChatUserProfileManager>();
|
||||||
final items = <_MenuRowData>[];
|
final items = <_MenuRowData>[];
|
||||||
@ -355,14 +417,6 @@ class _MePage2State extends State<MePage2> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
items.add(
|
|
||||||
_MenuRowData(
|
|
||||||
title: SCAppLocalizations.of(context)!.inviteActivity,
|
|
||||||
assetIcon: 'sc_images/index/sc_icon_invite_activity.png',
|
|
||||||
iconSize: 20,
|
|
||||||
onTap: _openInviteActivity,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. BD 相关(非管理员时)
|
// 2. BD 相关(非管理员时)
|
||||||
@ -451,17 +505,11 @@ class _MePage2State extends State<MePage2> {
|
|||||||
height: 46.w,
|
height: 46.w,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
Image.asset(
|
||||||
|
item.assetIcon!,
|
||||||
width: 24.w,
|
width: 24.w,
|
||||||
height: 24.w,
|
height: 24.w,
|
||||||
child: Center(
|
color: Colors.white,
|
||||||
child: Image.asset(
|
|
||||||
item.assetIcon!,
|
|
||||||
width: item.iconSize.w,
|
|
||||||
height: item.iconSize.w,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
|
||||||
SizedBox(width: 12.w),
|
SizedBox(width: 12.w),
|
||||||
@ -611,11 +659,9 @@ class _MenuRowData {
|
|||||||
required this.title,
|
required this.title,
|
||||||
required this.onTap,
|
required this.onTap,
|
||||||
this.assetIcon,
|
this.assetIcon,
|
||||||
this.iconSize = 24,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
final String? assetIcon;
|
final String? assetIcon;
|
||||||
final double iconSize;
|
|
||||||
final VoidCallback onTap;
|
final VoidCallback onTap;
|
||||||
}
|
}
|
||||||
|
|||||||
131
lib/shared/tools/sc_install_referrer_utils.dart
Normal file
131
lib/shared/tools/sc_install_referrer_utils.dart
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:yumi/shared/data_sources/sources/local/data_persistence.dart';
|
||||||
|
|
||||||
|
class SCInstallReferrerUtils {
|
||||||
|
static const MethodChannel _channel = MethodChannel(
|
||||||
|
'com.org.yumiparty/install_referrer',
|
||||||
|
);
|
||||||
|
static const String _cachedInviteCodeKey = 'install_referrer_invite_code';
|
||||||
|
static const String _cachedRawReferrerKey = 'install_referrer_raw';
|
||||||
|
|
||||||
|
static Future<String> getInviteCode() async {
|
||||||
|
final cachedInviteCode = DataPersistence.getString(_cachedInviteCodeKey);
|
||||||
|
if (cachedInviteCode.isNotEmpty) {
|
||||||
|
return cachedInviteCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
final cachedRawReferrer = DataPersistence.getString(_cachedRawReferrerKey);
|
||||||
|
if (cachedRawReferrer.isNotEmpty) {
|
||||||
|
return extractInviteCode(cachedRawReferrer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Platform.isAndroid) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final referrer = await _channel.invokeMethod<String>(
|
||||||
|
'getInstallReferrer',
|
||||||
|
);
|
||||||
|
if (referrer == null || referrer.trim().isEmpty) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
await DataPersistence.setString(_cachedRawReferrerKey, referrer);
|
||||||
|
final inviteCode = extractInviteCode(referrer);
|
||||||
|
if (inviteCode.isNotEmpty) {
|
||||||
|
await DataPersistence.setString(_cachedInviteCodeKey, inviteCode);
|
||||||
|
}
|
||||||
|
return inviteCode;
|
||||||
|
} on PlatformException catch (e) {
|
||||||
|
debugPrint('get install referrer failed: ${e.code} ${e.message}');
|
||||||
|
return '';
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('get install referrer failed: $e');
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static String extractInviteCode(String referrer) {
|
||||||
|
return _extractInviteCode(referrer, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String _extractInviteCode(String input, int depth) {
|
||||||
|
if (depth > 4) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
final value = input.trim();
|
||||||
|
if (value.isEmpty) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
final params = _queryParameters(value);
|
||||||
|
final inviteCode = _inviteCodeFromParams(params);
|
||||||
|
if (inviteCode.isNotEmpty) {
|
||||||
|
return inviteCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
final nestedReferrer = _nestedReferrerFromParams(params);
|
||||||
|
if (nestedReferrer != null && nestedReferrer.isNotEmpty) {
|
||||||
|
final nestedInviteCode = _extractInviteCode(nestedReferrer, depth + 1);
|
||||||
|
if (nestedInviteCode.isNotEmpty) {
|
||||||
|
return nestedInviteCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final decodedValue = _decodeComponent(value);
|
||||||
|
if (decodedValue != value) {
|
||||||
|
return _extractInviteCode(decodedValue, depth + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
static Map<String, String> _queryParameters(String value) {
|
||||||
|
final uri = Uri.tryParse(value);
|
||||||
|
if (uri != null && uri.hasQuery) {
|
||||||
|
return uri.queryParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!value.contains('=')) {
|
||||||
|
return const {};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return Uri.splitQueryString(value);
|
||||||
|
} catch (_) {
|
||||||
|
return const {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static String _inviteCodeFromParams(Map<String, String> params) {
|
||||||
|
for (final entry in params.entries) {
|
||||||
|
final key = entry.key.toLowerCase();
|
||||||
|
if (key == 'invite_code' || key == 'invitecode') {
|
||||||
|
return entry.value.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
static String? _nestedReferrerFromParams(Map<String, String> params) {
|
||||||
|
for (final entry in params.entries) {
|
||||||
|
if (entry.key.toLowerCase() == 'referrer') {
|
||||||
|
return entry.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String _decodeComponent(String value) {
|
||||||
|
try {
|
||||||
|
return Uri.decodeComponent(value);
|
||||||
|
} catch (_) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -210,6 +210,10 @@ class _SCSvgaAssetWidgetState extends State<SCSvgaAssetWidget>
|
|||||||
clearsAfterStop: widget.clearsAfterStop,
|
clearsAfterStop: widget.clearsAfterStop,
|
||||||
filterQuality: widget.filterQuality,
|
filterQuality: widget.filterQuality,
|
||||||
allowDrawingOverflow: widget.allowDrawingOverflow,
|
allowDrawingOverflow: widget.allowDrawingOverflow,
|
||||||
|
preferredSize:
|
||||||
|
widget.width != null && widget.height != null
|
||||||
|
? Size(widget.width!, widget.height!)
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 1.2.1+5
|
version: 1.2.2+6
|
||||||
|
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 398 B |
BIN
sc_images/index/sc_invite_activity.svga
Normal file
BIN
sc_images/index/sc_invite_activity.svga
Normal file
Binary file not shown.
BIN
sc_images/index/sc_invite_activity_fa.svga
Normal file
BIN
sc_images/index/sc_invite_activity_fa.svga
Normal file
Binary file not shown.
BIN
sc_images/index/sc_invite_activity_pt.svga
Normal file
BIN
sc_images/index/sc_invite_activity_pt.svga
Normal file
Binary file not shown.
BIN
sc_images/index/sc_invite_activity_rtl.svga
Normal file
BIN
sc_images/index/sc_invite_activity_rtl.svga
Normal file
Binary file not shown.
44
test/install_referrer_utils_test.dart
Normal file
44
test/install_referrer_utils_test.dart
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:yumi/shared/tools/sc_install_referrer_utils.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('SCInstallReferrerUtils.extractInviteCode', () {
|
||||||
|
test('extracts invite code from decoded referrer', () {
|
||||||
|
expect(
|
||||||
|
SCInstallReferrerUtils.extractInviteCode(
|
||||||
|
'invite_code=LZSWI6GO&source=share',
|
||||||
|
),
|
||||||
|
'LZSWI6GO',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('extracts invite code from encoded referrer', () {
|
||||||
|
expect(
|
||||||
|
SCInstallReferrerUtils.extractInviteCode(
|
||||||
|
'invite_code%3DLZSWI6GO%26source%3Dshare',
|
||||||
|
),
|
||||||
|
'LZSWI6GO',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('extracts invite code from play store url', () {
|
||||||
|
expect(
|
||||||
|
SCInstallReferrerUtils.extractInviteCode(
|
||||||
|
'https://play.google.com/store/apps/details'
|
||||||
|
'?id=com.org.yumiparty'
|
||||||
|
'&referrer=invite_code%3DLZSWI6GO%26source%3Dshare',
|
||||||
|
),
|
||||||
|
'LZSWI6GO',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('extracts invite code from camel case key', () {
|
||||||
|
expect(
|
||||||
|
SCInstallReferrerUtils.extractInviteCode(
|
||||||
|
'inviteCode=LZSWI6GO&source=share',
|
||||||
|
),
|
||||||
|
'LZSWI6GO',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user