Skip to content

Commit

Permalink
Added loading a server's root listing [#7]
Browse files Browse the repository at this point in the history
 * Added a logging subsystem for all platforms.
 * Added a dependency on Ktor to do the networking.
 * Changed Android to allow clear text HTTP requests.
  • Loading branch information
mcpierce committed Jun 30, 2024
1 parent 9acce4d commit e124351
Show file tree
Hide file tree
Showing 35 changed files with 1,052 additions and 186 deletions.
5 changes: 4 additions & 1 deletion androidVariant/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:name=".VariantApp"
android:allowBackup="false"
android:label="Variant"
android:supportsRtl="true"
android:usesCleartextTraffic="false"
android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class VariantApp : Application() {
},
viewModelsModule = module {
viewModel {
VariantViewModel(get())
VariantViewModel(get(), get())
}
})
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Variant - A digital comic book reading application for the iPad and Android tablets.
* Copyright (C) 2024, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

package org.comixedproject.variant.android.ui

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.List
import androidx.compose.material.icons.filled.AccountBox
import androidx.compose.material.icons.filled.Settings
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.navigation.NamedNavArgument
import androidx.navigation.NavType
import androidx.navigation.navArgument
import org.comixedproject.variant.android.R

enum class NavigationScreen(val route: String, val navArguments: List<NamedNavArgument>) {
ComicList("comics", emptyList()),
Servers("servers", emptyList()),
BrowserServer(
"servers?serverId={serverId}&linkId={linkId}", listOf(
navArgument("serverId") {
type = NavType.StringType
},
navArgument("linkId") {
type = NavType.StringType
nullable = true
})
),
Settings("settings", emptyList());

companion object {
val all = values()
}
}

enum class BottomBarItems(val label: Int, val icon: ImageVector, val screen: NavigationScreen) {
ServerList(R.string.serverButtonLabel, Icons.Filled.AccountBox, NavigationScreen.Servers),
ComicList(
R.string.comicsButtonLabel,
Icons.AutoMirrored.Filled.List,
NavigationScreen.ComicList
),
Settings(R.string.settingsButtonLabel, Icons.Filled.Settings, NavigationScreen.Settings);

companion object {
val all = values()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Variant - A digital comic book reading application for the iPad and Android tablets.
* Copyright (C) 2024, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

package org.comixedproject.variant.android.ui.server

import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.navigation.NavDestination
import org.comixedproject.variant.android.VariantTheme
import org.comixedproject.variant.android.ui.BottomBarItems


@Composable
fun BottomBar(
currentDestination: NavDestination?,
onScreenChange: (route: String) -> Unit
) {
var selectedItem by remember { mutableIntStateOf(0) }

NavigationBar {
BottomBarItems.all.forEachIndexed { index, item ->
NavigationBarItem(selected = selectedItem == index,
onClick = {
selectedItem = index
onScreenChange(item.screen.route)
},
label = { Text(text = stringResource(id = item.label)) },
icon = {
Icon(
imageVector = item.icon,
contentDescription = stringResource(id = item.label)
)
})
}
}
}

@Preview
@Composable
fun BottomBarPreview() {
VariantTheme {
BottomBar(null, onScreenChange = {})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,67 +18,94 @@

package org.comixedproject.variant.android.ui.server

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Icon
import androidx.compose.material3.Surface
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import org.comixedproject.variant.android.VariantTheme
import org.comixedproject.variant.android.ui.Screens
import org.comixedproject.variant.android.ui.NavigationScreen
import org.comixedproject.variant.shared.model.VariantViewModel
import org.comixedproject.variant.shared.platform.Logger
import org.koin.androidx.compose.getViewModel

private const val TAG = "HomeScreen"

@Composable
fun HomeScreen(viewModel: VariantViewModel = getViewModel()) {
val selectedItem = remember { mutableStateOf(Screens.ComicManagement) }
val navHost = rememberNavController()
val navBackStackEntry by navHost.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
val showBottomBar = remember { mutableStateOf(true) }
val navController = rememberNavController()

NavigationSuiteScaffold(
navigationSuiteItems = {
Screens.all.forEach { screen ->
item(
selected = selectedItem.value == screen,
onClick = { selectedItem.value = screen },
label = { Text(stringResource(id = screen.label)) },
icon = {
Icon(
imageVector = screen.icon,
contentDescription = stringResource(id = screen.label)
)
},
alwaysShowLabel = true
)
Scaffold(
topBar = { Text("Top Bar") },
bottomBar = {
if (showBottomBar.value) {
BottomBar(currentDestination = navController.currentBackStackEntryAsState().value?.destination,
onScreenChange = { route -> navController.navigate(route) })
}
}
) {
Box(modifier = Modifier.fillMaxSize()) {
Surface(modifier = Modifier.align(Alignment.Center)) {
when (selectedItem.value) {
Screens.ServerManagement -> ServerManagementScreen(
viewModel.servers,
onSaveServer = { server ->
viewModel.saveServer(server)
},
) { padding ->
Column(
modifier = Modifier
.padding(padding)
.fillMaxSize()
) {
NavHost(
modifier = Modifier,
navController = navController,
startDestination = NavigationScreen.Servers.route
) {
composable(
route = NavigationScreen.Servers.route
) {
ServerManagementScreen(
servers = viewModel.servers,
onSaveServer = { server -> viewModel.saveServer(server) },
onBrowseServer = { server ->
navController.navigate("servers?serverId=${server.id}&linkId=")
},
onBrowserServer = {},
onDeleteServer = { server ->
viewModel.deleteServer(server)
})

Screens.ComicManagement -> Text("Comic Book Management")
Screens.Settings -> Text("Settings")
onDeleteServer = { }
)
}
composable(
route = NavigationScreen.BrowserServer.route,
arguments = NavigationScreen.BrowserServer.navArguments
) { entry ->
val serverId = entry.arguments?.getString("serverId")
val linkId = entry.arguments?.getString("linkId").orEmpty()
Logger.d(TAG, "serverId=${serverId} linkId=${linkId}")
viewModel.servers.find { server -> server.id == serverId }?.let { server ->
var directory = ""
if (linkId.length > 0) {
viewModel.allLinks.find { link -> link.id == linkId }?.let { link ->
directory = link.link
}
}
viewModel.loadServerFeed(server, directory)
ServerBrowse(
server = server,
links = viewModel.links,
directory,
onLoadDirectory = { server, selectedLink ->
viewModel.loadServerFeed(server, selectedLink.link)
navController.navigate("servers?serverId=${server.id}&linkId=${selectedLink.id}")
})
}
}
composable(route = NavigationScreen.ComicList.route) {
Text("Comic List!")
}
composable(route = NavigationScreen.Settings.route) {
Text("Settings!")
}
}
}
Expand Down
Loading

0 comments on commit e124351

Please sign in to comment.