refactor: move profile editor and emoji pack screens to commonsUI

The upload port freed NewUserMetadataScreen, EmojiPackScreen and
EmojiPackMetadataScreen (7 files with their view models and the add-emoji
dialog). Record the upload port and the next blockers in the one-UI plan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7FuNBSKiyVecARSoE4B9P
This commit is contained in:
Claude
2026-09-29 15:41:49 +00:00
parent ccf1b7dce9
commit 815749b158
10 changed files with 44 additions and 24 deletions
@@ -59,6 +59,7 @@ import com.vitorpamplona.amethyst.commons.relayClient.user.LocalUserFinderAccoun
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.invalid_nip19_uri
import com.vitorpamplona.amethyst.commons.resources.invalid_nip19_uri_description
import com.vitorpamplona.amethyst.commons.ui.actions.NewUserMetadataScreen
import com.vitorpamplona.amethyst.commons.ui.layouts.LocalScreenLayout
import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.LocalTabReselectCoordinator
import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.TabReselectCoordinator
@@ -102,7 +103,9 @@ import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.communities.Communi
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.contactList.ContactListUsersScreen
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.drafts.DraftListScreen
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.browse.BrowseEmojiSetsScreen
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.display.EmojiPackScreen
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.list.ListOfEmojiPacksScreen
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.list.metadata.EmojiPackMetadataScreen
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.membershipManagement.EmojiPackSelectionScreen
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.membershipManagement.MyEmojiListScreen
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.favorites.FavoriteAppsScreen
@@ -184,7 +187,6 @@ import com.vitorpamplona.amethyst.service.relayClient.authCommand.compose.RelayA
import com.vitorpamplona.amethyst.service.relayClient.notifyCommand.compose.DisplayNotifyMessages
import com.vitorpamplona.amethyst.service.resourceusage.DisplayResourceUsageAlert
import com.vitorpamplona.amethyst.service.resourceusage.ScreenTimeIntegrator
import com.vitorpamplona.amethyst.ui.actions.NewUserMetadataScreen
import com.vitorpamplona.amethyst.ui.actions.bolt12Offers.Bolt12OffersScreen
import com.vitorpamplona.amethyst.ui.actions.mediaServers.AllMediaServersScreen
import com.vitorpamplona.amethyst.ui.actions.mediaServers.BlossomBlobManagerScreen
@@ -266,8 +268,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.embed.EmbeddedTabLayer
import com.vitorpamplona.amethyst.ui.screen.loggedIn.embed.EmbeddedTabPreloader
import com.vitorpamplona.amethyst.ui.screen.loggedIn.embed.EmbeddedTabThemeWatcher
import com.vitorpamplona.amethyst.ui.screen.loggedIn.embed.FavoriteAppManifestPreloader
import com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.display.EmojiPackScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.list.metadata.EmojiPackMetadataScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.favorites.NostrAppScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.feed.FollowPackFeedScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.list.FollowPacksScreen
@@ -59,6 +59,7 @@ import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserPicture
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.upload_image
import com.vitorpamplona.amethyst.commons.richtext.RichTextParser
import com.vitorpamplona.amethyst.commons.ui.actions.NewUserMetadataViewModel
import com.vitorpamplona.amethyst.commons.ui.actions.uploads.GallerySelectSingle
import com.vitorpamplona.amethyst.commons.ui.components.LoadingAnimation
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
@@ -69,7 +70,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp
import com.vitorpamplona.amethyst.commons.ui.theme.userProfileBorderModifier
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.commons.viewmodels.UserExternalIdentitiesViewModel
import com.vitorpamplona.amethyst.ui.actions.NewUserMetadataViewModel
import com.vitorpamplona.amethyst.ui.components.ZoomableImageDialog
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.header.apps.UserAppRecommendationsFeedViewModel
import kotlinx.coroutines.launch
@@ -413,11 +413,24 @@ assemblers, `EventSync`, …). Packages are renamed on the way:
- `MediaMimeTypes` moved to commons.
- **Wave 6 moved:** the NIP-46 signer screen. The other cuts clear blockers that sit
behind the upload stack.
- **Next:** the post-composer upload stack is now the main blocker, holding about 30
screens. `UploadOrchestrator`/`MultiOrchestrator` thread an Android `Context` through
compression, metadata stripping, encryption and the NIP-95/NIP-96/Blossom uploaders,
and the composer view models call them directly. The video player stack (media3) is
next at about 22. Smaller exits remain: the Android-only `AccountViewModel` actions,
- **Upload port (2026-09-29):**
- The upload model is in `commons.service.uploads`: `UploadOrchestrator`,
`MultiOrchestrator`, `UploadingState`, `CompressorQuality`, `MediaCompressorResult`
and the `MediaUploader` port.
- Errors are an `UploadError` enum. commonsUI maps it to a string (`errorResource`).
- The Android pipeline (compression, metadata stripping, encryption, the
NIP-95/NIP-96/Blossom uploaders) stays in the app as `AndroidMediaUploader`. It is
reached through `AccountViewModelHost.mediaUploader`.
- Composer view models take a `MediaUploader` instead of a `Context`.
- Five view models had their own copy of strip, compress and upload for a single
image. They now call the shared `uploadToDefaultServer`.
- Moved: the profile editor, the emoji pack screen and the emoji pack metadata screen
(7 files).
- **Next:** most composer screens still exit through `ShowImageUploadItem` (the upload
preview, which uses Android media APIs to show a thumbnail) and `SelectFromFiles`.
After those comes the per-composer state: `ShortNotePostViewModel`, `PreviewState`
and the location pickers. The video player stack (media3) holds about 22 screens.
Smaller exits remain: the Android-only `AccountViewModel` actions,
`CalendarTimeFormat`, `NestUiState`, `NappletLauncher`, `UpdateZapAmountDialog`
(biometrics), the `java.time` pickers and the language list.
7. **Navigation**: the library swap, then `AppNavigation` + rail + drawer + bottom bar.
@@ -18,7 +18,7 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.amethyst.ui.actions
package com.vitorpamplona.amethyst.commons.ui.actions
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.expandVertically
@@ -49,7 +49,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.commons.resources.Res
@@ -75,6 +74,7 @@ import com.vitorpamplona.amethyst.commons.resources.twitter_proof_url_template
import com.vitorpamplona.amethyst.commons.resources.username
import com.vitorpamplona.amethyst.commons.resources.website_url
import com.vitorpamplona.amethyst.commons.ui.actions.uploads.SelectSingleFromGallery
import com.vitorpamplona.amethyst.commons.ui.components.rememberViewModel
import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SavingTopBar
@@ -88,7 +88,7 @@ fun NewUserMetadataScreen(
nav: INav,
accountViewModel: AccountViewModel,
) {
val postViewModel: NewUserMetadataViewModel = viewModel()
val postViewModel: NewUserMetadataViewModel = rememberViewModel { NewUserMetadataViewModel() }
postViewModel.init(accountViewModel)
val socialExpanded = rememberSaveable { mutableStateOf(false) }
@@ -18,7 +18,7 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.amethyst.ui.actions
package com.vitorpamplona.amethyst.commons.ui.actions
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -18,7 +18,7 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.display
package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.display
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@@ -18,7 +18,7 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.display
package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.display
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
@@ -54,7 +54,6 @@ import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import coil3.compose.AsyncImage
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
@@ -68,6 +67,7 @@ import com.vitorpamplona.amethyst.commons.resources.quick_action_delete
import com.vitorpamplona.amethyst.commons.ui.components.M3ActionDialog
import com.vitorpamplona.amethyst.commons.ui.components.M3ActionRow
import com.vitorpamplona.amethyst.commons.ui.components.M3ActionSection
import com.vitorpamplona.amethyst.commons.ui.components.rememberViewModel
import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ShorterTopAppBar
@@ -84,7 +84,7 @@ fun EmojiPackScreen(
nav: INav,
) {
val viewModel: EmojiPackViewModel =
viewModel(
rememberViewModel(
factory = EmojiPackViewModel.Initializer(accountViewModel.account, packIdentifier),
)
EmojiPackScreenView(viewModel, accountViewModel, nav)
@@ -18,7 +18,7 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.display
package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.display
import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
@@ -27,15 +27,18 @@ import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.CreationExtras
import com.vitorpamplona.amethyst.commons.model.Account
import com.vitorpamplona.amethyst.commons.service.uploads.MediaUploader
import com.vitorpamplona.amethyst.commons.service.uploads.SelectedMedia
import com.vitorpamplona.amethyst.commons.ui.uploads.uploadToDefaultServer
import com.vitorpamplona.quartz.nip30CustomEmoji.EmojiUrlTag
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlin.reflect.KClass
@Stable
class EmojiPackViewModel(
@@ -101,7 +104,10 @@ class EmojiPackViewModel(
class Initializer(
val account: Account,
val packIdentifier: String,
) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T = EmojiPackViewModel(account, packIdentifier) as T
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(
modelClass: KClass<T>,
extras: CreationExtras,
): T = EmojiPackViewModel(account, packIdentifier) as T
}
}
@@ -18,7 +18,7 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.list.metadata
package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.list.metadata
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
@@ -58,7 +58,6 @@ import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDirection
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import coil3.compose.AsyncImage
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
@@ -71,6 +70,7 @@ import com.vitorpamplona.amethyst.commons.resources.emoji_pack_upload_image_cta
import com.vitorpamplona.amethyst.commons.resources.emoji_pack_upload_image_hint
import com.vitorpamplona.amethyst.commons.resources.new_emoji_pack
import com.vitorpamplona.amethyst.commons.ui.actions.uploads.GallerySelectSingle
import com.vitorpamplona.amethyst.commons.ui.components.rememberViewModel
import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.CreatingTopBar
@@ -85,7 +85,7 @@ fun EmojiPackMetadataScreen(
accountViewModel: AccountViewModel,
nav: INav,
) {
val viewModel: EmojiPackMetadataViewModel = viewModel()
val viewModel: EmojiPackMetadataViewModel = rememberViewModel { EmojiPackMetadataViewModel() }
viewModel.init(accountViewModel)
if (packIdentifier != null) {
@@ -18,7 +18,7 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.list.metadata
package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.list.metadata
import androidx.compose.runtime.Stable
import androidx.compose.runtime.derivedStateOf
@@ -40,6 +40,7 @@ import com.vitorpamplona.amethyst.commons.ui.uploads.uploadToDefaultServer
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.launch
@Stable