Skip to content

Commit d118f4d

Browse files
dadachiclaude
andcommitted
Phase 2A-2: Remove NFC / QR / Scan
Mirrors NativeAppTemplate-Android PR #39 (which itself mirrors iOS PR #50). After this, the app is a generic CRUD shell with Shops and Settings tabs; ItemTagDetailView is a placeholder (name, description, state, completedAt). ### Deletions - NfcError; ItemTagWriteView/VM + test - ui/scan/* (ScanView, ScanViewModel, DoScanView, DoScanViewModel, CompleteScanResultView, ShowTagInfoScanResultView, ScanNavigation) + DoScanViewModelTest - Models: CompleteScanResult, CompleteScanResultType, ShowTagInfoScanResult, ShowTagInfoScanResultType, ItemTagInfoFromNdefMessage, ItemTagType, ScanState, ItemTagData - Proto schemas: scan_result.proto, item_tag_data.proto, item_tag_info_from_ndef_message.proto - res/raw/nfc_reader.json ### Strip / rewrite - MainActivity: dropped NFC imports, onNewIntent, ACTION_NDEF_DISCOVERED handling, singleTask launch mode - MainActivityViewModel: rewritten minimal (logout + permissions refresh + didShowTapShopBelowTip) - NatAppState / NatNavHost / TopLevelDestination: dropped SCAN_TAB, shouldNavigateToScanView flow, navigateToScan helper, scan nav graph - ShopDetailView / VM: dropped queue instructions block, ReadInstructionsTip, didShowReadInstructionsTip; renamed resetItemTag -> idleItemTag and swipe action "Reset" -> "Idle" (width 64dp -> 96dp) - ShopSettingsView / VM: removed the "Reset Number Tags" section, resetShop flow - ItemTagDetailView / VM: placeholder (name, description, state, completedAt) - LoginRepository (+ Impl) / NatPreferencesDataSource: dropped scan-related setters/getters, didShowReadInstructionsTip - ShopRepository / ShopApi / Impl: dropped resetShop - ItemTagApi / Repository / Impl: renamed resetItemTag (/reset) -> idleItemTag (/idle) - Utility: dropped scanUri(), extractItemTagInfoFrom(), NFC imports - NatConstants: dropped SCAN_PATH, SCAN_PATH_CUSTOMER - UserData: dropped didShowReadInstructionsTip, scanViewSelectedTabIndex, shouldFetchItemTagForShowTagInfoScan, shouldCompleteItemTagForCompleteScan - shopSettingsNavigation: dropped ItemTagWriteRoute / itemTagWriteView - Demo / test repos updated to match trimmed interfaces; obsolete tests removed (UtilityTest scanUri, CodedErrorTest NfcError, ItemTagDetailVMTest isLock, ShopDetailVMTest reset/didShowReadInstructionsTip) ### Config - AndroidManifest.xml: removed NFC permission, android.hardware.nfc feature, NDEF_DISCOVERED intent-filter, singleTask launch mode - build.gradle.kts / libs.versions.toml: removed compose-qr-code, capturable, lottie-compose - user_preferences.proto: removed scan fields - strings.xml: removed ~25 scan/NFC/QR strings; onboarding descriptions 1-13 rewritten to generic "Welcome to the app." placeholder so OnboardingView still compiles (worth redesigning or deleting in a follow-up) ### Test plan - [x] ./gradlew assembleDebug passes - [x] ./gradlew test passes - [x] ./gradlew spotlessCheck passes - [x] ./gradlew lint passes - [x] ./gradlew buildHealth passes - [ ] Manual smoke test on device/emulator: 2 tabs visible (Shops / Settings), no Scan tab; sign-in works; ItemTag create / view detail placeholder / edit / delete flows work Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent ba89b56 commit d118f4d

63 files changed

Lines changed: 64 additions & 3930 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/build.gradle.kts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,10 @@ dependencies {
9696
implementation(libs.androidx.navigation.compose)
9797
implementation(libs.androidx.profileinstaller)
9898
implementation(libs.androidx.tracing.ktx)
99-
implementation(libs.capturable)
100-
implementation(libs.compose.qr.code)
10199
implementation(libs.hilt.android)
102100
implementation(libs.kotlin.stdlib.jdk8)
103101
implementation(libs.kotlinx.coroutines.guava)
104102
implementation(libs.kotlinx.serialization.json)
105-
implementation(libs.lottie.compose)
106103
implementation(libs.okhttp)
107104
implementation(libs.okhttp.logging.interceptor)
108105
implementation(libs.retrofit)

app/src/main/AndroidManifest.xml

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@
55
<uses-permission android:name="android.permission.INTERNET" />
66
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
77

8-
<uses-permission android:name="android.permission.NFC" />
9-
<uses-feature android:name="android.hardware.nfc" android:required="false" />
10-
118
<application
129
android:name=".NativeAppTemplateApplication"
1310
android:allowBackup="false"
@@ -21,26 +18,13 @@
2118
android:networkSecurityConfig="@xml/network_security_config"
2219
tools:ignore="GoogleAppIndexingWarning"
2320
tools:targetApi="tiramisu">
24-
<!--
25-
`singleTask` for Background Tag Reading. Avoid running MainActivity onCreate again with Background Tag Reading.
26-
https://qiita.com/takagimeow/items/48b37c55ad8d73d5da88
27-
-->
2821
<activity
2922
android:name=".MainActivity"
30-
android:exported="true"
31-
android:launchMode="singleTask">
23+
android:exported="true">
3224
<intent-filter>
3325
<action android:name="android.intent.action.MAIN" />
3426
<category android:name="android.intent.category.LAUNCHER" />
3527
</intent-filter>
36-
<intent-filter>
37-
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
38-
<category android:name="android.intent.category.DEFAULT" />
39-
<data android:scheme="https"
40-
android:host="api.nativeapptemplate.com"
41-
android:path="/scan"
42-
/>
43-
</intent-filter>
4428
</activity>
4529
<provider
4630
android:name="androidx.core.content.FileProvider"
@@ -52,4 +36,4 @@
5236
android:resource="@xml/filepaths" />
5337
</provider>
5438
</application>
55-
</manifest>
39+
</manifest>

app/src/main/kotlin/com/nativeapptemplate/nativeapptemplatefree/MainActivity.kt

Lines changed: 0 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
package com.nativeapptemplate.nativeapptemplatefree
22

3-
import android.content.Intent
43
import android.graphics.Color
5-
import android.nfc.NdefMessage
6-
import android.nfc.NfcAdapter
7-
import android.os.Build.VERSION.SDK_INT
84
import android.os.Bundle
95
import androidx.activity.ComponentActivity
106
import androidx.activity.SystemBarStyle
@@ -26,14 +22,11 @@ import com.nativeapptemplate.nativeapptemplatefree.MainActivityUiState.Success
2622
import com.nativeapptemplate.nativeapptemplatefree.data.login.LoginRepository
2723
import com.nativeapptemplate.nativeapptemplatefree.designsystem.theme.NatTheme
2824
import com.nativeapptemplate.nativeapptemplatefree.model.DarkThemeConfig
29-
import com.nativeapptemplate.nativeapptemplatefree.model.ItemTagInfoFromNdefMessage
3025
import com.nativeapptemplate.nativeapptemplatefree.ui.app_root.NatApp
3126
import com.nativeapptemplate.nativeapptemplatefree.ui.app_root.rememberNatAppState
3227
import com.nativeapptemplate.nativeapptemplatefree.utils.NetworkMonitor
33-
import com.nativeapptemplate.nativeapptemplatefree.utils.Utility
3428
import dagger.hilt.android.AndroidEntryPoint
3529
import kotlinx.coroutines.launch
36-
import java.util.Date
3730
import javax.inject.Inject
3831

3932
@AndroidEntryPoint
@@ -51,16 +44,6 @@ class MainActivity : ComponentActivity() {
5144
val splashScreen = installSplashScreen()
5245
super.onCreate(savedInstanceState)
5346

54-
viewModel.updateShouldNavigateToScanView(false)
55-
viewModel.updateShouldFetchItemTagForShowTagInfoScan(false)
56-
viewModel.updateShouldCompleteItemTagForCompleteScan(false)
57-
viewModel.initScanViewSelectedTabIndex()
58-
viewModel.initShowTagInfoScanResult()
59-
viewModel.initCompleteScanResult()
60-
61-
// viewModel.updateDidShowTapShopBelowTip(false)
62-
// viewModel.updateDidShowReadInstructionsTip(false)
63-
6447
// Update the uiState
6548
lifecycleScope.launch {
6649
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
@@ -117,86 +100,12 @@ class MainActivity : ComponentActivity() {
117100
NatApp(appState)
118101
}
119102
}
120-
121-
if (!uiState.isLoggedIn) return
122-
123-
val intent = intent
124-
if (NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action) {
125-
viewModel.updateShouldNavigateToScanView(false)
126-
127-
val ndefMessage: NdefMessage?
128-
val rawMessages = if (SDK_INT >= 33) { // TIRAMISU
129-
intent.getParcelableArrayExtra(
130-
NfcAdapter.EXTRA_NDEF_MESSAGES,
131-
NdefMessage::class.java,
132-
)
133-
} else {
134-
@Suppress("DEPRECATION")
135-
intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)
136-
}
137-
138-
if (!rawMessages.isNullOrEmpty()) {
139-
ndefMessage = rawMessages[0] as NdefMessage
140-
141-
val itemTagInfoFromNdefMessage = Utility.extractItemTagInfoFrom(
142-
context = this,
143-
ndefMessage = ndefMessage,
144-
)
145-
146-
updateItemTagInfoFromNdefMessage(itemTagInfoFromNdefMessage)
147-
viewModel.initScanViewSelectedTabIndex()
148-
viewModel.updateShouldNavigateToScanView(true)
149-
}
150-
}
151-
}
152-
153-
override fun onNewIntent(intent: Intent) {
154-
super.onNewIntent(intent)
155-
156-
if (!uiState.isLoggedIn) return
157-
158-
if (NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action) {
159-
viewModel.updateShouldNavigateToScanView(false)
160-
161-
val ndefMessage: NdefMessage?
162-
val rawMessages = if (SDK_INT >= 33) { // TIRAMISU
163-
intent.getParcelableArrayExtra(
164-
NfcAdapter.EXTRA_NDEF_MESSAGES,
165-
NdefMessage::class.java,
166-
)
167-
} else {
168-
@Suppress("DEPRECATION")
169-
intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)
170-
}
171-
172-
if (!rawMessages.isNullOrEmpty()) {
173-
ndefMessage = rawMessages[0] as NdefMessage
174-
175-
val itemTagInfoFromNdefMessage = Utility.extractItemTagInfoFrom(
176-
context = this,
177-
ndefMessage = ndefMessage,
178-
)
179-
180-
updateItemTagInfoFromNdefMessage(itemTagInfoFromNdefMessage)
181-
viewModel.initScanViewSelectedTabIndex()
182-
viewModel.updateShouldNavigateToScanView(true)
183-
}
184-
}
185103
}
186104

187105
override fun onResume() {
188106
super.onResume()
189107
viewModel.updatePermissions()
190108
}
191-
192-
private fun updateItemTagInfoFromNdefMessage(itemTagInfoFromNdefMessage: ItemTagInfoFromNdefMessage) {
193-
if (itemTagInfoFromNdefMessage.success) {
194-
itemTagInfoFromNdefMessage.scannedAt = Date().toInstant().toString()
195-
}
196-
197-
viewModel.updateItemTagInfoFromNdefMessage(itemTagInfoFromNdefMessage)
198-
viewModel.updateShouldCompleteItemTagForCompleteScan(itemTagInfoFromNdefMessage.success)
199-
}
200109
}
201110

202111
/**

app/src/main/kotlin/com/nativeapptemplate/nativeapptemplatefree/MainActivityViewModel.kt

Lines changed: 0 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,8 @@ import androidx.lifecycle.ViewModel
55
import androidx.lifecycle.viewModelScope
66
import com.nativeapptemplate.nativeapptemplatefree.MainActivityUiState.Loading
77
import com.nativeapptemplate.nativeapptemplatefree.MainActivityUiState.Success
8-
import com.nativeapptemplate.nativeapptemplatefree.common.errors.codedDescription
98
import com.nativeapptemplate.nativeapptemplatefree.data.login.LoginRepository
10-
import com.nativeapptemplate.nativeapptemplatefree.model.CompleteScanResult
11-
import com.nativeapptemplate.nativeapptemplatefree.model.CompleteScanResultType
12-
import com.nativeapptemplate.nativeapptemplatefree.model.ItemTagInfoFromNdefMessage
139
import com.nativeapptemplate.nativeapptemplatefree.model.Permissions
14-
import com.nativeapptemplate.nativeapptemplatefree.model.ShowTagInfoScanResult
1510
import com.nativeapptemplate.nativeapptemplatefree.model.UserData
1611
import dagger.hilt.android.lifecycle.HiltViewModel
1712
import kotlinx.coroutines.flow.Flow
@@ -37,54 +32,12 @@ class MainActivityViewModel @Inject constructor(
3732
started = SharingStarted.WhileSubscribed(5_000),
3833
)
3934

40-
fun updateShouldFetchItemTagForShowTagInfoScan(shouldFetchItemTagForShowTagInfoScan: Boolean) {
41-
viewModelScope.launch {
42-
loginRepository.setShouldFetchItemTagForShowTagInfoScan(shouldFetchItemTagForShowTagInfoScan)
43-
}
44-
}
45-
46-
fun updateShouldCompleteItemTagForCompleteScan(shouldCompleteItemTagForCompleteScan: Boolean) {
47-
viewModelScope.launch {
48-
loginRepository.setShouldCompleteItemTagForCompleteScan(shouldCompleteItemTagForCompleteScan)
49-
}
50-
}
51-
52-
fun updateShouldNavigateToScanView(shouldNavigateToScanView: Boolean) {
53-
viewModelScope.launch {
54-
loginRepository.setShouldNavigateToScanView(shouldNavigateToScanView)
55-
}
56-
}
57-
58-
fun initScanViewSelectedTabIndex() {
59-
viewModelScope.launch {
60-
loginRepository.setScanViewSelectedTabIndex(0)
61-
}
62-
}
63-
64-
fun initShowTagInfoScanResult() {
65-
viewModelScope.launch {
66-
loginRepository.setShowTagInfoScanResult(ShowTagInfoScanResult())
67-
}
68-
}
69-
70-
fun initCompleteScanResult() {
71-
viewModelScope.launch {
72-
loginRepository.setCompleteScanResult(CompleteScanResult())
73-
}
74-
}
75-
7635
fun updateDidShowTapShopBelowTip(didShowTapShopBelowTip: Boolean) {
7736
viewModelScope.launch {
7837
loginRepository.setDidShowTapShopBelowTip(didShowTapShopBelowTip)
7938
}
8039
}
8140

82-
fun updateDidShowReadInstructionsTip(didShowReadInstructionsTip: Boolean) {
83-
viewModelScope.launch {
84-
loginRepository.setDidShowReadInstructionsTip(didShowReadInstructionsTip)
85-
}
86-
}
87-
8841
fun updatePermissions() {
8942
viewModelScope.launch {
9043
val isLoggedIn = loginRepository.isLoggedIn().first()
@@ -110,30 +63,6 @@ class MainActivityViewModel @Inject constructor(
11063
}
11164
}
11265
}
113-
114-
fun updateItemTagInfoFromNdefMessage(
115-
itemTagInfoFromNdefMessage: ItemTagInfoFromNdefMessage,
116-
) {
117-
viewModelScope.launch {
118-
val completeScanResult = CompleteScanResult()
119-
completeScanResult.itemTagInfoFromNdefMessage = itemTagInfoFromNdefMessage
120-
121-
if (!completeScanResult.itemTagInfoFromNdefMessage.success) {
122-
completeScanResult.message = itemTagInfoFromNdefMessage.message
123-
completeScanResult.completeScanResultType = CompleteScanResultType.Failed
124-
}
125-
126-
try {
127-
loginRepository.setCompleteScanResult(completeScanResult)
128-
} catch (exception: Exception) {
129-
val message = exception.codedDescription
130-
completeScanResult.message = message
131-
completeScanResult.completeScanResultType = CompleteScanResultType.Failed
132-
133-
loginRepository.setCompleteScanResult(completeScanResult)
134-
}
135-
}
136-
}
13766
}
13867

13968
sealed interface MainActivityUiState {

app/src/main/kotlin/com/nativeapptemplate/nativeapptemplatefree/NatConstants.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
package com.nativeapptemplate.nativeapptemplatefree
22

33
object NatConstants {
4-
const val SCAN_PATH: String = "scan"
5-
const val SCAN_PATH_CUSTOMER: String = "scan_customer"
6-
74
const val SUPPORT_MAIL: String = "support@nativeapptemplate.com"
85
const val HOW_TO_USE_URL: String = "https://myturntag.com/how"
96
const val SUPPORT_WEBSITE_URL: String = "https://nativeapptemplate.com"

app/src/main/kotlin/com/nativeapptemplate/nativeapptemplatefree/common/errors/NfcError.kt

Lines changed: 0 additions & 12 deletions
This file was deleted.

app/src/main/kotlin/com/nativeapptemplate/nativeapptemplatefree/data/item_tag/ItemTagApi.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ interface ItemTagApi {
4545
@Path("id") id: String,
4646
): ApiResponse<ItemTag>
4747

48-
@PATCH("{account_id}/api/v1/shopkeeper/item_tags/{id}/reset")
49-
suspend fun resetItemTag(
48+
@PATCH("{account_id}/api/v1/shopkeeper/item_tags/{id}/idle")
49+
suspend fun idleItemTag(
5050
@Path("account_id") accountId: String,
5151
@Path("id") id: String,
5252
): ApiResponse<ItemTag>

app/src/main/kotlin/com/nativeapptemplate/nativeapptemplatefree/data/item_tag/ItemTagRepository.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ interface ItemTagRepository {
3131
id: String,
3232
): Flow<ItemTag>
3333

34-
fun resetItemTag(
34+
fun idleItemTag(
3535
id: String,
3636
): Flow<ItemTag>
3737
}

app/src/main/kotlin/com/nativeapptemplate/nativeapptemplatefree/data/item_tag/ItemTagRepositoryImpl.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,10 @@ class ItemTagRepositoryImpl @Inject constructor(
7777
emitApiResponse(response)
7878
}.flowOn(ioDispatcher)
7979

80-
override fun resetItemTag(
80+
override fun idleItemTag(
8181
id: String,
8282
) = flow {
83-
val response = api.resetItemTag(mtcPreferencesDataSource.userData.first().accountId, id)
83+
val response = api.idleItemTag(mtcPreferencesDataSource.userData.first().accountId, id)
8484
emitApiResponse(response)
8585
}.flowOn(ioDispatcher)
8686
}

app/src/main/kotlin/com/nativeapptemplate/nativeapptemplatefree/data/login/LoginRepository.kt

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,6 @@ interface LoginRepository {
2020

2121
fun updateConfirmedTermsVersion(): Flow<Boolean>
2222

23-
suspend fun setShouldFetchItemTagForShowTagInfoScan(shouldFetchItemTagForShowTagInfoScan: Boolean)
24-
25-
suspend fun setShouldCompleteItemTagForCompleteScan(shouldCompleteItemTagForCompleteScan: Boolean)
26-
27-
suspend fun setShouldNavigateToScanView(shouldNavigateToScanView: Boolean)
28-
29-
suspend fun setScanViewSelectedTabIndex(scanViewSelectedTabIndex: Int)
30-
31-
suspend fun setCompleteScanResult(completeScanResult: CompleteScanResult)
32-
33-
suspend fun setShowTagInfoScanResult(showTagInfoScanResult: ShowTagInfoScanResult)
34-
3523
suspend fun setAccountId(accountId: String)
3624

3725
suspend fun setShopkeeper(loggedInShopkeeper: LoggedInShopkeeper)
@@ -42,8 +30,6 @@ interface LoginRepository {
4230

4331
suspend fun setDidShowTapShopBelowTip(didShowTapShopBelowTip: Boolean)
4432

45-
suspend fun setDidShowReadInstructionsTip(didShowReadInstructionsTip: Boolean)
46-
4733
suspend fun setDarkThemeConfig(darkThemeConfig: DarkThemeConfig)
4834

4935
suspend fun setIsEmailUpdated(isEmailUpdated: Boolean)
@@ -70,19 +56,5 @@ interface LoginRepository {
7056

7157
fun didShowTapShopBelowTip(): Flow<Boolean>
7258

73-
fun didShowReadInstructionsTip(): Flow<Boolean>
74-
7559
fun getMaximumQueueNumberLength(): Flow<Int>
76-
77-
fun shouldFetchItemTagForShowTagInfoScan(): Flow<Boolean>
78-
79-
fun shouldCompleteItemTagForCompleteScan(): Flow<Boolean>
80-
81-
fun shouldNavigateToScanView(): Flow<Boolean>
82-
83-
fun scanViewSelectedTabIndex(): Flow<Int>
84-
85-
fun completeScanResult(): Flow<CompleteScanResult>
86-
87-
fun showTagInfoScanResult(): Flow<ShowTagInfoScanResult>
8860
}

0 commit comments

Comments
 (0)