diff --git a/UIViews/build.gradle b/UIViews/build.gradle index bc2f87d6b..a92010e3d 100644 --- a/UIViews/build.gradle +++ b/UIViews/build.gradle @@ -63,6 +63,8 @@ dependencies { implementation 'com.github.pwittchen:reactivenetwork-rx2:3.0.8' + implementation koin.koin + implementation project(':Models') implementation project(':favoritesdatabase') diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/AllFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/AllFragment.kt index 939dca0ec..ce3d7f1bc 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/AllFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/AllFragment.kt @@ -64,7 +64,7 @@ class AllFragment : BaseListFragment() { binding.allList.apply { adapter = this@AllFragment.adapter - layoutManager = createLayoutManager(this@AllFragment.requireContext()) + layoutManager = info.createLayoutManager(this@AllFragment.requireContext()) addOnScrollListener(object : EndlessScrollingListener(layoutManager!!) { override fun onLoadMore(page: Int, totalItemsCount: Int, view: RecyclerView?) { if (sourcePublish.value!!.canScroll && binding.searchInfo.text.isNullOrEmpty()) { diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/BaseListFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/BaseListFragment.kt index 1472fb2f4..fa5b3a2b9 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/BaseListFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/BaseListFragment.kt @@ -4,12 +4,15 @@ import android.os.Bundle import android.view.View import androidx.annotation.CallSuper import androidx.recyclerview.widget.RecyclerView +import org.koin.android.ext.android.inject -abstract class BaseListFragment : BaseFragment(), GenericInfo by BaseMainActivity.genericInfo { +abstract class BaseListFragment : BaseFragment() { protected lateinit var adapter: ItemListAdapter<RecyclerView.ViewHolder> + protected val info: GenericInfo by inject() + @CallSuper override fun viewCreated(view: View, savedInstanceState: Bundle?) { - adapter = createAdapter(this@BaseListFragment.requireContext(), this) + adapter = info.createAdapter(this@BaseListFragment.requireContext(), this) } } \ No newline at end of file diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/BaseMainActivity.kt b/UIViews/src/main/java/com/programmersbox/uiviews/BaseMainActivity.kt index c62ceb49c..7b5249750 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/BaseMainActivity.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/BaseMainActivity.kt @@ -16,22 +16,23 @@ import com.squareup.okhttp.Request import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.addTo import kotlinx.coroutines.launch -import kotlin.properties.Delegates +import org.koin.android.ext.android.inject -abstract class BaseMainActivity : AppCompatActivity(), GenericInfo { +abstract class BaseMainActivity : AppCompatActivity() { protected val disposable = CompositeDisposable() private var currentNavController: LiveData<NavController>? = null + protected val genericInfo: GenericInfo by inject() + protected abstract fun onCreate() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - genericInfo = this setContentView(R.layout.base_main_activity) - toSource(currentService.orEmpty())?.let { sourcePublish.onNext(it) } + genericInfo.toSource(currentService.orEmpty())?.let { sourcePublish.onNext(it) } if (savedInstanceState == null) { setupBottomNavBar() @@ -112,8 +113,4 @@ abstract class BaseMainActivity : AppCompatActivity(), GenericInfo { super.onDestroy() } - companion object { - var genericInfo by Delegates.notNull<GenericInfo>() - } - } \ No newline at end of file diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt index 680097bf9..cd704e102 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt @@ -36,6 +36,7 @@ import io.reactivex.rxkotlin.subscribeBy import io.reactivex.schedulers.Schedulers import io.reactivex.subjects.BehaviorSubject import me.zhanghai.android.fastscroll.FastScrollerBuilder +import org.koin.android.ext.android.inject class DetailsFragment : Fragment() { @@ -51,7 +52,7 @@ class DetailsFragment : Fragment() { private val disposable = CompositeDisposable() - private val adapter by lazy { ChapterAdapter(requireContext(), BaseMainActivity.genericInfo, dao) } + private val adapter by lazy { ChapterAdapter(requireContext(), inject<GenericInfo>().value, dao) } private val itemListener = FirebaseDb.FirebaseListener() private val chapterListener = FirebaseDb.FirebaseListener() diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/FavoriteFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/FavoriteFragment.kt index d2c1adee5..5b07925ee 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/FavoriteFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/FavoriteFragment.kt @@ -33,6 +33,7 @@ import io.reactivex.rxkotlin.Flowables import io.reactivex.rxkotlin.addTo import io.reactivex.schedulers.Schedulers import io.reactivex.subjects.BehaviorSubject +import org.koin.android.ext.android.inject import java.util.concurrent.TimeUnit class FavoriteFragment : BaseFragment() { @@ -40,7 +41,8 @@ class FavoriteFragment : BaseFragment() { private val dao by lazy { ItemDatabase.getInstance(requireContext()).itemDao() } private val disposable = CompositeDisposable() - private val sources by lazy { BaseMainActivity.genericInfo.sourceList() } + private val genericInfo by inject<GenericInfo>() + private val sources by lazy { genericInfo.sourceList() } private val sourcePublisher = BehaviorSubject.createDefault(sources.toMutableList()) private var sourcesList by behaviorDelegate(sourcePublisher) private val adapter by lazy { FavoriteAdapter() } @@ -164,12 +166,12 @@ class FavoriteFragment : BaseFragment() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FavoriteHolder = FavoriteHolder(FavoriteItemBinding.inflate(requireContext().layoutInflater, parent, false)) - override fun FavoriteHolder.onBind(item: Pair<String, List<DbModel>>, position: Int) = bind(item.second) + override fun FavoriteHolder.onBind(item: Pair<String, List<DbModel>>, position: Int) = bind(item.second, genericInfo) } class FavoriteHolder(private val binding: FavoriteItemBinding) : RecyclerView.ViewHolder(binding.root) { - fun bind(info: List<DbModel>) { + fun bind(info: List<DbModel>, genericInfo: GenericInfo) { binding.show = info.random() Glide.with(itemView.context) .asBitmap() @@ -183,13 +185,13 @@ class FavoriteFragment : BaseFragment() { binding.root.setOnClickListener { if (info.size == 1) { - val item = info.firstOrNull()?.let { BaseMainActivity.genericInfo.toSource(it.source)?.let { it1 -> it.toItemModel(it1) } } + val item = info.firstOrNull()?.let { genericInfo.toSource(it.source)?.let { it1 -> it.toItemModel(it1) } } binding.root.findNavController().navigate(FavoriteFragmentDirections.actionFavoriteFragmentToDetailsFragment(item)) } else { MaterialAlertDialogBuilder(itemView.context) .setTitle(R.string.chooseASource) .setItems(info.map { "${it.source} - ${it.title}" }.toTypedArray()) { d, i -> - val item = info[i].let { BaseMainActivity.genericInfo.toSource(it.source)?.let { it1 -> it.toItemModel(it1) } } + val item = info[i].let { genericInfo.toSource(it.source)?.let { it1 -> it.toItemModel(it1) } } binding.root.findNavController().navigate(FavoriteFragmentDirections.actionFavoriteFragmentToDetailsFragment(item)) d.dismiss() } diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/OtakuApp.kt b/UIViews/src/main/java/com/programmersbox/uiviews/OtakuApp.kt index 12225f016..52dcb8c0c 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/OtakuApp.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/OtakuApp.kt @@ -13,6 +13,9 @@ import com.programmersbox.helpfulutils.createNotificationGroup import com.programmersbox.loggingutils.Loged import com.programmersbox.uiviews.utils.shouldCheck import io.reactivex.plugins.RxJavaPlugins +import org.koin.android.ext.koin.androidContext +import org.koin.android.ext.koin.androidLogger +import org.koin.core.context.startKoin import java.util.concurrent.TimeUnit abstract class OtakuApp : Application() { @@ -35,6 +38,11 @@ abstract class OtakuApp : Application() { //FirebaseCrashlytics.getInstance().recordException(it) } + startKoin { + androidLogger() + androidContext(this@OtakuApp) + } + onCreated() val work = WorkManager.getInstance(this) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/RecentFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/RecentFragment.kt index d6fcf4d40..7cfe67c2f 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/RecentFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/RecentFragment.kt @@ -52,7 +52,7 @@ class RecentFragment : BaseListFragment() { binding.recentList.apply { adapter = this@RecentFragment.adapter - layoutManager = createLayoutManager(this@RecentFragment.requireContext()) + layoutManager = info.createLayoutManager(this@RecentFragment.requireContext()) addOnScrollListener(object : EndlessScrollingListener(layoutManager!!) { override fun onLoadMore(page: Int, totalItemsCount: Int, view: RecyclerView?) { if (sourcePublish.value!!.canScroll) { diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt index 1c84e7694..813aedad3 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt @@ -41,6 +41,7 @@ import io.reactivex.rxkotlin.addTo import io.reactivex.rxkotlin.subscribeBy import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.* +import org.koin.android.ext.android.inject import java.io.File import java.io.FileOutputStream import java.io.IOException @@ -56,11 +57,11 @@ class SettingsFragment : PreferenceFragmentCompat() { private val disposable: CompositeDisposable = CompositeDisposable() + private val genericInfo: GenericInfo by inject() + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.root_preferences, rootKey) - val genericInfo = BaseMainActivity.genericInfo - accountPreferences() generalPreferences(genericInfo) aboutPreferences(genericInfo) diff --git a/animeworld/build.gradle b/animeworld/build.gradle index 1ff5ddd32..d28f23d52 100644 --- a/animeworld/build.gradle +++ b/animeworld/build.gradle @@ -113,4 +113,6 @@ dependencies { //Custom Libraries implementation jakepurple13Tools.helpfultools + + implementation koin.koin } \ No newline at end of file diff --git a/animeworld/src/main/java/com/programmersbox/animeworld/AnimeApp.kt b/animeworld/src/main/java/com/programmersbox/animeworld/AnimeApp.kt index d30394ec3..ec5146384 100644 --- a/animeworld/src/main/java/com/programmersbox/animeworld/AnimeApp.kt +++ b/animeworld/src/main/java/com/programmersbox/animeworld/AnimeApp.kt @@ -22,12 +22,15 @@ import com.tonyodev.fetch2.* import com.tonyodev.fetch2.Fetch.Impl.setDefaultInstanceConfiguration import com.tonyodev.fetch2core.Downloader import com.tonyodev.fetch2core.deleteFile +import org.koin.core.context.loadKoinModules import java.net.HttpURLConnection import javax.net.ssl.* class AnimeApp : OtakuApp() { override fun onCreated() { + loadKoinModules(appModule) + logo = R.mipmap.ic_launcher notificationLogo = R.mipmap.ic_launcher_foreground diff --git a/animeworld/src/main/java/com/programmersbox/animeworld/GenericAnime.kt b/animeworld/src/main/java/com/programmersbox/animeworld/GenericAnime.kt new file mode 100644 index 000000000..3e8873f0c --- /dev/null +++ b/animeworld/src/main/java/com/programmersbox/animeworld/GenericAnime.kt @@ -0,0 +1,286 @@ +package com.programmersbox.animeworld + +import android.Manifest +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.widget.Toast +import androidx.core.content.ContextCompat +import androidx.lifecycle.lifecycleScope +import androidx.mediarouter.app.MediaRouteDialogFactory +import androidx.preference.Preference +import androidx.preference.SwitchPreference +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.google.android.gms.cast.framework.CastContext +import com.obsez.android.lib.filechooser.ChooserDialog +import com.programmersbox.anime_sources.Sources +import com.programmersbox.anime_sources.anime.Movies +import com.programmersbox.anime_sources.anime.Torrents +import com.programmersbox.anime_sources.anime.WcoStream +import com.programmersbox.anime_sources.anime.Yts +import com.programmersbox.animeworld.cast.ExpandedControlsActivity +import com.programmersbox.animeworld.ytsdatabase.Torrent +import com.programmersbox.gsonutils.fromJson +import com.programmersbox.helpfulutils.requestPermissions +import com.programmersbox.helpfulutils.runOnUIThread +import com.programmersbox.helpfulutils.sharedPrefNotNullDelegate +import com.programmersbox.models.ApiService +import com.programmersbox.models.ChapterModel +import com.programmersbox.models.sourcePublish +import com.programmersbox.uiviews.BaseListFragment +import com.programmersbox.uiviews.GenericInfo +import com.programmersbox.uiviews.ItemListAdapter +import com.programmersbox.uiviews.SettingsDsl +import com.tonyodev.fetch2.* +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.addTo +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import org.koin.dsl.module + +val appModule = module { + single<GenericInfo> { GenericAnime(get()) } +} + +class GenericAnime(val context: Context) : GenericInfo { + + private var Context.wcoRecent by sharedPrefNotNullDelegate(true) + + private val disposable = CompositeDisposable() + + override val showMiddleChapterButton: Boolean + get() = true + + override val apkString: String + get() = "animeworld-debug.apk" + + override fun createAdapter(context: Context, baseListFragment: BaseListFragment): ItemListAdapter<RecyclerView.ViewHolder> = + (AnimeAdapter(context, baseListFragment) as ItemListAdapter<RecyclerView.ViewHolder>) + + override fun createLayoutManager(context: Context): RecyclerView.LayoutManager = LinearLayoutManager(context) + + override fun downloadChapter(chapterModel: ChapterModel, title: String) { + if (chapterModel.source == Yts) { + Toast.makeText(context, R.string.yts_no_stream, Toast.LENGTH_SHORT).show() + return + } + MainActivity.activity.lifecycleScope.launch(Dispatchers.IO) { + val link = chapterModel.getChapterInfo().blockingGet().firstOrNull()?.link + MainActivity.activity.runOnUiThread { + MainActivity.activity.startActivity( + Intent(context, VideoPlayerActivity::class.java).apply { + putExtra("showPath", link) + putExtra("showName", chapterModel.name) + putExtra("downloadOrStream", true) + } + ) + } + } + } + + private val fetch = Fetch.getDefaultInstance() + + override fun chapterOnClick(model: ChapterModel, allChapters: List<ChapterModel>, context: Context) { + MainActivity.activity.requestPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE) { p -> + if (p.isGranted) { + Toast.makeText(context, R.string.downloading_dots_no_percent, Toast.LENGTH_SHORT).show() + + when (model.source) { + Yts -> { + val f = model.extras["torrents"].toString().fromJson<Torrents>()?.let { + val m = model.extras["info"].toString().fromJson<Movies>() + Torrent( + title = m?.title.orEmpty(), + banner_url = m?.background_image.orEmpty(), + url = it.url.orEmpty(), + hash = it.hash.orEmpty(), + quality = it.quality.orEmpty(), + type = it.type.orEmpty(), + seeds = it.seeds?.toInt() ?: 0, + peers = it.peers?.toInt() ?: 0, + size_pretty = it.size.orEmpty(), + size = it.size_bytes?.toLong() ?: 0L, + date_uploaded = it.date_uploaded.orEmpty(), + date_uploaded_unix = it.date_uploaded_unix.toString(), + movieId = m?.id?.toInt() ?: 0, + imdbCode = m?.imdb_code.orEmpty(), + ) + } + + val serviceIntent = Intent(context, DownloadService::class.java) + serviceIntent.putExtra(DownloadService.TORRENT_JOB, f) + context.startService(serviceIntent) + } + else -> { + GlobalScope.launch { fetchIt(model) } + } + } + } + } + } + + private fun fetchIt(ep: ChapterModel) { + + fetch.setGlobalNetworkType(NetworkType.ALL) + + fun getNameFromUrl(url: String): String { + return Uri.parse(url).lastPathSegment?.let { if (it.isNotEmpty()) it else ep.name } ?: ep.name + } + + val requestList = arrayListOf<Request>() + val url = ep.getChapterInfo() + .doOnError { runOnUIThread { Toast.makeText(context, R.string.something_went_wrong, Toast.LENGTH_SHORT).show() } } + .onErrorReturnItem(emptyList()) + .blockingGet() + for (i in url) { + + val filePath = context.folderLocation + getNameFromUrl(i.link!!) + "${ep.name}.mp4" + val request = Request(i.link!!, filePath) + request.priority = Priority.HIGH + request.networkType = NetworkType.ALL + request.enqueueAction = EnqueueAction.REPLACE_EXISTING + request.extras.map.toProperties()["URL_INTENT"] = ep.url + request.extras.map.toProperties()["NAME_INTENT"] = ep.name + + request.addHeader("Accept-Language", "en-US,en;q=0.5") + request.addHeader("User-Agent", "\"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0\"") + request.addHeader("Accept", "text/html,video/mp4,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8") + request.addHeader("Access-Control-Allow-Origin", "*") + request.addHeader("Referer", "http://thewebsite.com") + request.addHeader("Connection", "keep-alive") + + i.headers.entries.forEach { request.headers[it.key] = it.value } + + requestList.add(request) + + } + fetch.enqueue(requestList) {} + } + + override fun sourceList(): List<ApiService> = Sources.values().toList() + + override fun toSource(s: String): ApiService? = try { + Sources.valueOf(s) + } catch (e: IllegalArgumentException) { + null + } + + override fun customPreferences(preferenceScreen: SettingsDsl) { + + preferenceScreen.viewSettings { + it.addPreference( + Preference(it.context).apply { + title = context.getString(R.string.video_menu_title) + icon = ContextCompat.getDrawable(it.context, R.drawable.ic_baseline_video_library_24) + setOnPreferenceClickListener { + openVideos() + true + } + } + ) + + val casting = Preference(it.context).apply { + title = context.getString(R.string.cast_menu_title) + icon = ContextCompat.getDrawable(it.context, R.drawable.ic_baseline_cast_24) + setOnPreferenceClickListener { + if (MainActivity.cast.isCastActive()) { + context.startActivity(Intent(context, ExpandedControlsActivity::class.java)) + } else { + MediaRouteDialogFactory.getDefault().onCreateChooserDialogFragment() + .also { it.routeSelector = CastContext.getSharedInstance(context).mergedSelector } + .show(MainActivity.activity.supportFragmentManager, "media_chooser") + } + true + } + } + + MainActivity.cast.sessionConnected() + .subscribe(casting::setVisible) + .addTo(disposable) + + MainActivity.cast.sessionStatus() + .map { if (it) R.drawable.ic_baseline_cast_connected_24 else R.drawable.ic_baseline_cast_24 } + .subscribe(casting::setIcon) + .addTo(disposable) + + it.addPreference(casting) + + it.addPreference( + Preference(it.context).apply { + title = context.getString(R.string.downloads_menu_title) + icon = ContextCompat.getDrawable(it.context, R.drawable.ic_baseline_download_24) + setOnPreferenceClickListener { + openDownloads() + true + } + } + ) + } + + preferenceScreen.generalSettings { + + it.addPreference( + SwitchPreference(it.context).apply { + title = context.getString(R.string.wco_recent_title) + summary = context.getString(R.string.wco_recent_info) + key = "wco_recent" + isChecked = context.wcoRecent + setOnPreferenceChangeListener { _, newValue -> + WcoStream.RECENT_TYPE = newValue as Boolean + context.wcoRecent = newValue + true + } + icon = ContextCompat.getDrawable(it.context, R.drawable.ic_baseline_article_24) + sourcePublish.subscribe { api -> + isVisible = api == Sources.WCO_CARTOON || api == Sources.WCO_DUBBED || + api == Sources.WCO_MOVIES || api == Sources.WCO_SUBBED || api == Sources.WCO_OVA + } + .addTo(disposable) + } + ) + + it.addPreference( + Preference(it.context).apply { + title = context.getString(R.string.folder_location) + summary = it.context.folderLocation + icon = ContextCompat.getDrawable(it.context, R.drawable.ic_baseline_folder_24) + setOnPreferenceClickListener { + MainActivity.activity.requestPermissions( + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE, + ) { + if (it.isGranted) { + ChooserDialog(context) + .withIcon(R.mipmap.ic_launcher) + .withResources(R.string.choose_a_directory, R.string.chooseText, R.string.cancelText) + .withFilter(true, false) + .withStartFile(context.folderLocation) + .enableOptions(true) + .withChosenListener { dir, _ -> + context.folderLocation = "$dir/" + println(dir) + summary = context.folderLocation + } + .build() + .show() + } + } + true + } + } + ) + } + + } + + private fun openDownloads() { + DownloadViewerFragment().show(MainActivity.activity.supportFragmentManager, "downloadViewer") + } + + private fun openVideos() { + ViewVideosFragment().show(MainActivity.activity.supportFragmentManager, "videoViewer") + } + +} diff --git a/animeworld/src/main/java/com/programmersbox/animeworld/MainActivity.kt b/animeworld/src/main/java/com/programmersbox/animeworld/MainActivity.kt index fbebc00a7..30ea0643e 100644 --- a/animeworld/src/main/java/com/programmersbox/animeworld/MainActivity.kt +++ b/animeworld/src/main/java/com/programmersbox/animeworld/MainActivity.kt @@ -1,47 +1,21 @@ package com.programmersbox.animeworld -import android.Manifest import android.content.Context -import android.content.Intent import android.net.Uri -import android.widget.Toast -import androidx.core.content.ContextCompat -import androidx.lifecycle.lifecycleScope -import androidx.mediarouter.app.MediaRouteDialogFactory -import androidx.preference.Preference -import androidx.preference.SwitchPreference -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import com.google.android.gms.cast.framework.CastContext -import com.obsez.android.lib.filechooser.ChooserDialog import com.programmersbox.anime_sources.Sources -import com.programmersbox.anime_sources.anime.* +import com.programmersbox.anime_sources.anime.WcoStream import com.programmersbox.animeworld.cast.CastHelper -import com.programmersbox.animeworld.cast.ExpandedControlsActivity -import com.programmersbox.animeworld.ytsdatabase.Torrent -import com.programmersbox.gsonutils.fromJson -import com.programmersbox.helpfulutils.requestPermissions import com.programmersbox.helpfulutils.sharedPrefNotNullDelegate -import com.programmersbox.models.ApiService -import com.programmersbox.models.ChapterModel import com.programmersbox.models.sourcePublish -import com.programmersbox.uiviews.BaseListFragment import com.programmersbox.uiviews.BaseMainActivity -import com.programmersbox.uiviews.ItemListAdapter -import com.programmersbox.uiviews.SettingsDsl import com.programmersbox.uiviews.utils.currentService -import com.tonyodev.fetch2.* -import io.reactivex.rxkotlin.addTo -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch class MainActivity : BaseMainActivity() { companion object { const val VIEW_DOWNLOADS = "animeworld://view_downloads" const val VIEW_VIDEOS = "animeworld://view_videos" - private lateinit var activity: MainActivity + lateinit var activity: MainActivity val cast: CastHelper = CastHelper() } @@ -69,231 +43,6 @@ class MainActivity : BaseMainActivity() { } - override val showMiddleChapterButton: Boolean - get() = true - - override val apkString: String - get() = "animeworld-debug.apk" - - override fun createAdapter(context: Context, baseListFragment: BaseListFragment): ItemListAdapter<RecyclerView.ViewHolder> = - (AnimeAdapter(context, baseListFragment) as ItemListAdapter<RecyclerView.ViewHolder>) - - override fun createLayoutManager(context: Context): RecyclerView.LayoutManager = LinearLayoutManager(context) - - override fun downloadChapter(chapterModel: ChapterModel, title: String) { - if (chapterModel.source == Yts) { - Toast.makeText(this, R.string.yts_no_stream, Toast.LENGTH_SHORT).show() - return - } - lifecycleScope.launch(Dispatchers.IO) { - val link = chapterModel.getChapterInfo().blockingGet().firstOrNull()?.link - runOnUiThread { - startActivity( - Intent(this@MainActivity, VideoPlayerActivity::class.java).apply { - putExtra("showPath", link) - putExtra("showName", chapterModel.name) - putExtra("downloadOrStream", true) - } - ) - } - } - } - - private val fetch = Fetch.getDefaultInstance() - - override fun chapterOnClick(model: ChapterModel, allChapters: List<ChapterModel>, context: Context) { - requestPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE) { p -> - if (p.isGranted) { - Toast.makeText(this, R.string.downloading_dots_no_percent, Toast.LENGTH_SHORT).show() - - when (model.source) { - Yts -> { - val f = model.extras["torrents"].toString().fromJson<Torrents>()?.let { - val m = model.extras["info"].toString().fromJson<Movies>() - Torrent( - title = m?.title.orEmpty(), - banner_url = m?.background_image.orEmpty(), - url = it.url.orEmpty(), - hash = it.hash.orEmpty(), - quality = it.quality.orEmpty(), - type = it.type.orEmpty(), - seeds = it.seeds?.toInt() ?: 0, - peers = it.peers?.toInt() ?: 0, - size_pretty = it.size.orEmpty(), - size = it.size_bytes?.toLong() ?: 0L, - date_uploaded = it.date_uploaded.orEmpty(), - date_uploaded_unix = it.date_uploaded_unix.toString(), - movieId = m?.id?.toInt() ?: 0, - imdbCode = m?.imdb_code.orEmpty(), - ) - } - - val serviceIntent = Intent(this, DownloadService::class.java) - serviceIntent.putExtra(DownloadService.TORRENT_JOB, f) - startService(serviceIntent) - } - else -> { - GlobalScope.launch { fetchIt(model) } - } - } - } - } - } - - private fun fetchIt(ep: ChapterModel) { - - fetch.setGlobalNetworkType(NetworkType.ALL) - - fun getNameFromUrl(url: String): String { - return Uri.parse(url).lastPathSegment?.let { if (it.isNotEmpty()) it else ep.name } ?: ep.name - } - - val requestList = arrayListOf<Request>() - val url = ep.getChapterInfo() - .doOnError { runOnUiThread { Toast.makeText(this@MainActivity, R.string.something_went_wrong, Toast.LENGTH_SHORT).show() } } - .onErrorReturnItem(emptyList()) - .blockingGet() - for (i in url) { - - val filePath = folderLocation + getNameFromUrl(i.link!!) + "${ep.name}.mp4" - val request = Request(i.link!!, filePath) - request.priority = Priority.HIGH - request.networkType = NetworkType.ALL - request.enqueueAction = EnqueueAction.REPLACE_EXISTING - request.extras.map.toProperties()["URL_INTENT"] = ep.url - request.extras.map.toProperties()["NAME_INTENT"] = ep.name - - request.addHeader("Accept-Language", "en-US,en;q=0.5") - request.addHeader("User-Agent", "\"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0\"") - request.addHeader("Accept", "text/html,video/mp4,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8") - request.addHeader("Access-Control-Allow-Origin", "*") - request.addHeader("Referer", "http://thewebsite.com") - request.addHeader("Connection", "keep-alive") - - i.headers.entries.forEach { request.headers[it.key] = it.value } - - requestList.add(request) - - } - fetch.enqueue(requestList) {} - } - - override fun sourceList(): List<ApiService> = Sources.values().toList() - - override fun toSource(s: String): ApiService? = try { - Sources.valueOf(s) - } catch (e: IllegalArgumentException) { - null - } - - override fun customPreferences(preferenceScreen: SettingsDsl) { - - preferenceScreen.viewSettings { - it.addPreference( - Preference(it.context).apply { - title = getString(R.string.video_menu_title) - icon = ContextCompat.getDrawable(it.context, R.drawable.ic_baseline_video_library_24) - setOnPreferenceClickListener { - openVideos() - true - } - } - ) - - val casting = Preference(it.context).apply { - title = getString(R.string.cast_menu_title) - icon = ContextCompat.getDrawable(it.context, R.drawable.ic_baseline_cast_24) - setOnPreferenceClickListener { - if (cast.isCastActive()) { - startActivity(Intent(this@MainActivity, ExpandedControlsActivity::class.java)) - } else { - MediaRouteDialogFactory.getDefault().onCreateChooserDialogFragment() - .also { it.routeSelector = CastContext.getSharedInstance(applicationContext).mergedSelector } - .show(activity.supportFragmentManager, "media_chooser") - } - true - } - } - - cast.sessionConnected() - .subscribe(casting::setVisible) - .addTo(disposable) - - cast.sessionStatus() - .map { if (it) R.drawable.ic_baseline_cast_connected_24 else R.drawable.ic_baseline_cast_24 } - .subscribe(casting::setIcon) - .addTo(disposable) - - it.addPreference(casting) - - it.addPreference( - Preference(it.context).apply { - title = getString(R.string.downloads_menu_title) - icon = ContextCompat.getDrawable(it.context, R.drawable.ic_baseline_download_24) - setOnPreferenceClickListener { - openDownloads() - true - } - } - ) - } - - preferenceScreen.generalSettings { - - it.addPreference( - SwitchPreference(it.context).apply { - title = getString(R.string.wco_recent_title) - summary = getString(R.string.wco_recent_info) - key = "wco_recent" - isChecked = wcoRecent - setOnPreferenceChangeListener { _, newValue -> - WcoStream.RECENT_TYPE = newValue as Boolean - wcoRecent = newValue - true - } - icon = ContextCompat.getDrawable(it.context, R.drawable.ic_baseline_article_24) - sourcePublish.subscribe { - isVisible = it == Sources.WCO_CARTOON || it == Sources.WCO_DUBBED || - it == Sources.WCO_MOVIES || it == Sources.WCO_SUBBED || it == Sources.WCO_OVA - } - .addTo(disposable) - } - ) - - it.addPreference( - Preference(it.context).apply { - title = getString(R.string.folder_location) - summary = it.context.folderLocation - icon = ContextCompat.getDrawable(it.context, R.drawable.ic_baseline_folder_24) - setOnPreferenceClickListener { - requestPermissions( - Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.WRITE_EXTERNAL_STORAGE, - ) { - if (it.isGranted) { - ChooserDialog(this@MainActivity) - .withIcon(R.mipmap.ic_launcher) - .withResources(R.string.choose_a_directory, R.string.chooseText, R.string.cancelText) - .withFilter(true, false) - .withStartFile(folderLocation) - .enableOptions(true) - .withChosenListener { dir, _ -> - folderLocation = "$dir/" - println(dir) - summary = folderLocation - } - .build() - .show() - } - } - true - } - } - ) - } - - } - private fun openDownloads() { DownloadViewerFragment().show(activity.supportFragmentManager, "downloadViewer") } diff --git a/build.gradle b/build.gradle index e212350a0..7b1ca1fd3 100644 --- a/build.gradle +++ b/build.gradle @@ -37,6 +37,13 @@ buildscript { ext.room_version = "2.3.0" + def koin_version = "3.0.2" + + // Koin main features for Android (Scope,ViewModel ...) + ext.koinAndroid = "io.insert-koin:koin-android:$koin_version" + // Koin Android - experimental builder extensions + ext.koinAndroidExt = "io.insert-koin:koin-android-ext:$koin_version" + ext { jakepurple13Tools = [ helpfultools: [flowutils, gsonutils, helpfulutils, loggingutils, dragswipe, funutils, rxutils, thirdpartyutils] @@ -48,6 +55,8 @@ buildscript { "androidx.room:room-rxjava2:$room_version" ] ] + + koin = [koin: [koinAndroid, koinAndroidExt]] } repositories { diff --git a/mangaworld/build.gradle b/mangaworld/build.gradle index 6f8681a60..4be761774 100644 --- a/mangaworld/build.gradle +++ b/mangaworld/build.gradle @@ -87,4 +87,6 @@ dependencies { //Custom Libraries implementation jakepurple13Tools.helpfultools + + implementation koin.koin } \ No newline at end of file diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/GenericManga.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/GenericManga.kt new file mode 100644 index 000000000..628051aca --- /dev/null +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/GenericManga.kt @@ -0,0 +1,102 @@ +package com.programmersbox.mangaworld + +import android.Manifest +import android.app.DownloadManager +import android.content.Context +import android.content.Intent +import android.os.Environment +import androidx.core.net.toUri +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.programmersbox.gsonutils.toJson +import com.programmersbox.helpfulutils.downloadManager +import com.programmersbox.helpfulutils.requestPermissions +import com.programmersbox.manga_sources.Sources +import com.programmersbox.models.ApiService +import com.programmersbox.models.ChapterModel +import com.programmersbox.models.Storage +import com.programmersbox.uiviews.BaseListFragment +import com.programmersbox.uiviews.GenericInfo +import com.programmersbox.uiviews.ItemListAdapter +import com.programmersbox.uiviews.utils.AutoFitGridLayoutManager +import com.programmersbox.uiviews.utils.ChapterModelSerializer +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.addTo +import io.reactivex.rxkotlin.subscribeBy +import io.reactivex.schedulers.Schedulers +import org.koin.dsl.module +import java.io.File + +val appModule = module { + single<GenericInfo> { GenericManga(get()) } +} + +class GenericManga(val context: Context) : GenericInfo { + + private val disposable = CompositeDisposable() + + override val showMiddleChapterButton: Boolean get() = false + + override val apkString: String get() = "mangaworld-debug.apk" + + override fun createAdapter(context: Context, baseListFragment: BaseListFragment): ItemListAdapter<RecyclerView.ViewHolder> = + (MangaGalleryAdapter(context, baseListFragment) as ItemListAdapter<RecyclerView.ViewHolder>) + + override fun createLayoutManager(context: Context): RecyclerView.LayoutManager = + AutoFitGridLayoutManager(context, 360).apply { orientation = GridLayoutManager.VERTICAL } + + override fun chapterOnClick(model: ChapterModel, allChapters: List<ChapterModel>, context: Context) { + + context.startActivity( + Intent(context, ReadActivity::class.java).apply { + putExtra("currentChapter", model.toJson(ChapterModel::class.java to ChapterModelSerializer())) + putExtra("allChapters", allChapters.toJson(ChapterModel::class.java to ChapterModelSerializer())) + putExtra("mangaTitle", model.name) + putExtra("mangaUrl", model.url) + } + ) + + } + + private fun downloadFullChapter(model: ChapterModel, title: String) { + val fileLocation = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString() + "/MangaWorld/" + + val direct = File("$fileLocation$title/${model.name}/") + if (!direct.exists()) direct.mkdir() + + model.getChapterInfo() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .map { it.mapNotNull(Storage::link) } + .map { + it.mapIndexed { index, s -> + DownloadManager.Request(s.toUri()) + .setDestinationInExternalPublicDir(Environment.DIRECTORY_PICTURES, "MangaWorld/$title/${model.name}/$index.png") + .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) + .setAllowedOverRoaming(true) + .setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE or DownloadManager.Request.NETWORK_WIFI) + .setMimeType("image/jpeg") + .setTitle(model.name) + .addRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) Gecko/20100101 Firefox/77") + .addRequestHeader("Accept-Language", "en-US,en;q=0.5") + } + } + .subscribeBy { it.forEach(context.downloadManager::enqueue) } + .addTo(disposable) + } + + override fun downloadChapter(chapterModel: ChapterModel, title: String) { + MainActivity.activity.requestPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE) { p -> + if (p.isGranted) downloadFullChapter(chapterModel, title) + } + } + + override fun sourceList(): List<ApiService> = Sources.values().toList() + + override fun toSource(s: String): ApiService? = try { + Sources.valueOf(s) + } catch (e: IllegalArgumentException) { + null + } +} \ No newline at end of file diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/MainActivity.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/MainActivity.kt index cdc0ffb5f..4688cc0f0 100644 --- a/mangaworld/src/main/java/com/programmersbox/mangaworld/MainActivity.kt +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/MainActivity.kt @@ -1,38 +1,22 @@ package com.programmersbox.mangaworld -import android.Manifest -import android.app.DownloadManager -import android.content.Context -import android.content.Intent -import android.os.Environment -import androidx.core.net.toUri -import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.RecyclerView import com.github.piasy.biv.BigImageViewer import com.github.piasy.biv.loader.glide.GlideImageLoader -import com.programmersbox.gsonutils.toJson -import com.programmersbox.helpfulutils.downloadManager -import com.programmersbox.helpfulutils.requestPermissions import com.programmersbox.manga_sources.Sources -import com.programmersbox.models.ApiService -import com.programmersbox.models.ChapterModel import com.programmersbox.models.sourcePublish -import com.programmersbox.uiviews.BaseListFragment import com.programmersbox.uiviews.BaseMainActivity -import com.programmersbox.uiviews.ItemListAdapter -import com.programmersbox.uiviews.utils.AutoFitGridLayoutManager -import com.programmersbox.uiviews.utils.ChapterModelSerializer import com.programmersbox.uiviews.utils.currentService -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.rxkotlin.addTo -import io.reactivex.rxkotlin.subscribeBy -import io.reactivex.schedulers.Schedulers -import java.io.File class MainActivity : BaseMainActivity() { + companion object { + lateinit var activity: MainActivity + } + override fun onCreate() { + activity = this + BigImageViewer.initialize(GlideImageLoader.with(applicationContext)) if (currentService == null) { @@ -41,70 +25,4 @@ class MainActivity : BaseMainActivity() { } } - override val showMiddleChapterButton: Boolean - get() = false - - override val apkString: String - get() = "mangaworld-debug.apk" - - override fun createAdapter(context: Context, baseListFragment: BaseListFragment): ItemListAdapter<RecyclerView.ViewHolder> = - (MangaGalleryAdapter(context, baseListFragment) as ItemListAdapter<RecyclerView.ViewHolder>) - - override fun createLayoutManager(context: Context): RecyclerView.LayoutManager = - AutoFitGridLayoutManager(context, 360).apply { orientation = GridLayoutManager.VERTICAL } - - override fun chapterOnClick(model: ChapterModel, allChapters: List<ChapterModel>, context: Context) { - - startActivity( - Intent(this, ReadActivity::class.java).apply { - putExtra("currentChapter", model.toJson(ChapterModel::class.java to ChapterModelSerializer())) - putExtra("allChapters", allChapters.toJson(ChapterModel::class.java to ChapterModelSerializer())) - putExtra("mangaTitle", model.name) - putExtra("mangaUrl", model.url) - } - ) - - } - - private fun downloadFullChapter(model: ChapterModel, title: String) { - val fileLocation = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString() + "/MangaWorld/" - - val direct = File("$fileLocation$title/${model.name}/") - if (!direct.exists()) direct.mkdir() - - model.getChapterInfo() - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .map { it.mapNotNull { it.link } } - .map { - it.mapIndexed { index, s -> - DownloadManager.Request(s.toUri()) - .setDestinationInExternalPublicDir(Environment.DIRECTORY_PICTURES, "MangaWorld/$title/${model.name}/$index.png") - .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) - .setAllowedOverRoaming(true) - .setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE or DownloadManager.Request.NETWORK_WIFI) - .setMimeType("image/jpeg") - .setTitle(model.name) - .addRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) Gecko/20100101 Firefox/77") - .addRequestHeader("Accept-Language", "en-US,en;q=0.5") - } - } - .subscribeBy { it.forEach { downloadManager.enqueue(it) } } - .addTo(disposable) - } - - override fun downloadChapter(chapterModel: ChapterModel, title: String) { - requestPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE) { p -> - if (p.isGranted) downloadFullChapter(chapterModel, title) - } - } - - override fun sourceList(): List<ApiService> = Sources.values().toList() - - override fun toSource(s: String): ApiService? = try { - Sources.valueOf(s) - } catch (e: IllegalArgumentException) { - null - } - -} +} \ No newline at end of file diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/MangaApp.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/MangaApp.kt index bc2f40fd0..74bb01dd6 100644 --- a/mangaworld/src/main/java/com/programmersbox/mangaworld/MangaApp.kt +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/MangaApp.kt @@ -8,10 +8,13 @@ import com.programmersbox.manga_sources.Sources import com.programmersbox.uiviews.OtakuApp import com.programmersbox.uiviews.UpdateWorker import com.programmersbox.uiviews.utils.FirebaseDb +import org.koin.core.context.loadKoinModules class MangaApp : OtakuApp() { override fun onCreated() { + loadKoinModules(appModule) + logo = R.mipmap.ic_launcher notificationLogo = R.drawable.manga_world_round_logo diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt index 7f054c840..165961c12 100644 --- a/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt @@ -26,9 +26,10 @@ import com.programmersbox.gsonutils.fromJson import com.programmersbox.helpfulutils.* import com.programmersbox.mangaworld.databinding.ActivityReadBinding import com.programmersbox.models.ChapterModel +import com.programmersbox.models.Storage import com.programmersbox.rxutils.invoke import com.programmersbox.rxutils.toLatestFlowable -import com.programmersbox.uiviews.BaseMainActivity +import com.programmersbox.uiviews.GenericInfo import com.programmersbox.uiviews.utils.ChapterModelDeserializer import com.programmersbox.uiviews.utils.batteryAlertPercent import io.reactivex.android.schedulers.AndroidSchedulers @@ -38,6 +39,7 @@ import io.reactivex.rxkotlin.addTo import io.reactivex.rxkotlin.subscribeBy import io.reactivex.schedulers.Schedulers import io.reactivex.subjects.PublishSubject +import org.koin.android.ext.android.inject import java.io.File import java.util.* import kotlin.math.roundToInt @@ -70,11 +72,14 @@ class ReadActivity : AppCompatActivity() { } }*/ + + private val genericInfo by inject<GenericInfo>() + private val adapter2: PageAdapter by lazy { loader.let { val list = intent.getStringExtra("allChapters") - ?.fromJson<List<ChapterModel>>(ChapterModel::class.java to ChapterModelDeserializer(BaseMainActivity.genericInfo)) - .orEmpty().also { println(it) } + ?.fromJson<List<ChapterModel>>(ChapterModel::class.java to ChapterModelDeserializer(genericInfo)) + .orEmpty().also(::println) //intent.getObjectExtra<List<ChapterModel>>("allChapters") ?: emptyList() val url = intent.getStringExtra("mangaUrl") ?: "" val mangaUrl = intent.getStringExtra("mangaInfoUrl") ?: "" @@ -173,7 +178,7 @@ class ReadActivity : AppCompatActivity() { mangaTitle = intent.getStringExtra("mangaTitle") model = intent.getStringExtra("currentChapter") - ?.fromJson<ChapterModel>(ChapterModel::class.java to ChapterModelDeserializer(BaseMainActivity.genericInfo)) + ?.fromJson<ChapterModel>(ChapterModel::class.java to ChapterModelDeserializer(genericInfo)) //titleManga.text = mangaTitle loadPages(model) @@ -204,7 +209,7 @@ class ReadActivity : AppCompatActivity() { .start() adapter2.setListNotify(emptyList()) model?.getChapterInfo() - ?.map { it.mapNotNull { it.link } } + ?.map { it.mapNotNull(Storage::link) } ?.subscribeOn(Schedulers.io()) ?.observeOn(AndroidSchedulers.mainThread()) ?.doOnError { Toast.makeText(this, it.localizedMessage, Toast.LENGTH_SHORT).show() } @@ -217,7 +222,7 @@ class ReadActivity : AppCompatActivity() { .start() adapter2.setListNotify(pages) //adapter.addItems(pages) - binding.readView.layoutManager!!.scrollToPosition(model?.url?.let { defaultSharedPref.getInt(it, 0) } ?: 0) + //binding.readView.layoutManager!!.scrollToPosition(model.url.let { defaultSharedPref.getInt(it, 0) }) } ?.addTo(disposable) } diff --git a/novelworld/build.gradle b/novelworld/build.gradle index 27e6afc53..a27372317 100644 --- a/novelworld/build.gradle +++ b/novelworld/build.gradle @@ -74,4 +74,6 @@ dependencies { //Custom Libraries implementation jakepurple13Tools.helpfultools + + implementation koin.koin } \ No newline at end of file diff --git a/novelworld/src/main/java/com/programmersbox/novelworld/GenericNovel.kt b/novelworld/src/main/java/com/programmersbox/novelworld/GenericNovel.kt new file mode 100644 index 000000000..3c4bcf91f --- /dev/null +++ b/novelworld/src/main/java/com/programmersbox/novelworld/GenericNovel.kt @@ -0,0 +1,50 @@ +package com.programmersbox.novelworld + +import android.content.Context +import android.content.Intent +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.programmersbox.gsonutils.toJson +import com.programmersbox.models.ApiService +import com.programmersbox.models.ChapterModel +import com.programmersbox.novel_sources.Sources +import com.programmersbox.uiviews.BaseListFragment +import com.programmersbox.uiviews.GenericInfo +import com.programmersbox.uiviews.ItemListAdapter +import com.programmersbox.uiviews.utils.ChapterModelSerializer +import org.koin.dsl.module + +val appModule = module { + single<GenericInfo> { GenericNovel(get()) } +} + +class GenericNovel(val context: Context) : GenericInfo { + override fun createAdapter(context: Context, baseListFragment: BaseListFragment): ItemListAdapter<RecyclerView.ViewHolder> = + (NovelAdapter(context, baseListFragment) as ItemListAdapter<RecyclerView.ViewHolder>) + + override fun createLayoutManager(context: Context): RecyclerView.LayoutManager = LinearLayoutManager(context) + + override fun chapterOnClick(model: ChapterModel, allChapters: List<ChapterModel>, context: Context) { + context.startActivity( + Intent(context, ReadingActivity::class.java).apply { + putExtra("model", model.toJson(ChapterModel::class.java to ChapterModelSerializer())) + } + ) + } + + override fun sourceList(): List<ApiService> = Sources.values().toList() + + override fun toSource(s: String): ApiService? = try { + Sources.valueOf(s) + } catch (e: IllegalArgumentException) { + null + } + + override fun downloadChapter(chapterModel: ChapterModel, title: String) { + + } + + override val apkString: String get() = "novelworld-debug.apk" + + override val showMiddleChapterButton: Boolean get() = false +} \ No newline at end of file diff --git a/novelworld/src/main/java/com/programmersbox/novelworld/MainActivity.kt b/novelworld/src/main/java/com/programmersbox/novelworld/MainActivity.kt index 9f300d0a5..a9d114fbf 100644 --- a/novelworld/src/main/java/com/programmersbox/novelworld/MainActivity.kt +++ b/novelworld/src/main/java/com/programmersbox/novelworld/MainActivity.kt @@ -1,18 +1,8 @@ package com.programmersbox.novelworld -import android.content.Context -import android.content.Intent -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import com.programmersbox.gsonutils.toJson -import com.programmersbox.models.ApiService -import com.programmersbox.models.ChapterModel import com.programmersbox.models.sourcePublish import com.programmersbox.novel_sources.Sources -import com.programmersbox.uiviews.BaseListFragment import com.programmersbox.uiviews.BaseMainActivity -import com.programmersbox.uiviews.ItemListAdapter -import com.programmersbox.uiviews.utils.ChapterModelSerializer import com.programmersbox.uiviews.utils.currentService class MainActivity : BaseMainActivity() { @@ -27,33 +17,4 @@ class MainActivity : BaseMainActivity() { } - override fun createAdapter(context: Context, baseListFragment: BaseListFragment): ItemListAdapter<RecyclerView.ViewHolder> = - (NovelAdapter(context, baseListFragment) as ItemListAdapter<RecyclerView.ViewHolder>) - - override fun createLayoutManager(context: Context): RecyclerView.LayoutManager = LinearLayoutManager(context) - - override fun chapterOnClick(model: ChapterModel, allChapters: List<ChapterModel>, context: Context) { - startActivity( - Intent(this, ReadingActivity::class.java).apply { - putExtra("model", model.toJson(ChapterModel::class.java to ChapterModelSerializer())) - } - ) - } - - override fun sourceList(): List<ApiService> = Sources.values().toList() - - override fun toSource(s: String): ApiService? = try { - Sources.valueOf(s) - } catch (e: IllegalArgumentException) { - null - } - - override fun downloadChapter(chapterModel: ChapterModel, title: String) { - - } - - override val apkString: String get() = "novelworld-debug.apk" - - override val showMiddleChapterButton: Boolean get() = false - } \ No newline at end of file diff --git a/novelworld/src/main/java/com/programmersbox/novelworld/NovelApp.kt b/novelworld/src/main/java/com/programmersbox/novelworld/NovelApp.kt index 6fbe8a2cd..4f230e8cb 100644 --- a/novelworld/src/main/java/com/programmersbox/novelworld/NovelApp.kt +++ b/novelworld/src/main/java/com/programmersbox/novelworld/NovelApp.kt @@ -4,10 +4,13 @@ import com.programmersbox.novel_sources.Sources import com.programmersbox.uiviews.OtakuApp import com.programmersbox.uiviews.UpdateWorker import com.programmersbox.uiviews.utils.FirebaseDb +import org.koin.core.context.loadKoinModules class NovelApp : OtakuApp() { override fun onCreated() { + loadKoinModules(appModule) + logo = R.mipmap.ic_launcher notificationLogo = R.mipmap.ic_launcher_foreground diff --git a/novelworld/src/main/java/com/programmersbox/novelworld/ReadingActivity.kt b/novelworld/src/main/java/com/programmersbox/novelworld/ReadingActivity.kt index 86fd04977..64114e1d6 100644 --- a/novelworld/src/main/java/com/programmersbox/novelworld/ReadingActivity.kt +++ b/novelworld/src/main/java/com/programmersbox/novelworld/ReadingActivity.kt @@ -16,7 +16,7 @@ import com.programmersbox.models.ChapterModel import com.programmersbox.novelworld.databinding.ActivityReadingBinding import com.programmersbox.rxutils.invoke import com.programmersbox.rxutils.toLatestFlowable -import com.programmersbox.uiviews.BaseMainActivity +import com.programmersbox.uiviews.GenericInfo import com.programmersbox.uiviews.utils.ChapterModelDeserializer import com.programmersbox.uiviews.utils.batteryAlertPercent import io.reactivex.android.schedulers.AndroidSchedulers @@ -26,6 +26,7 @@ import io.reactivex.rxkotlin.addTo import io.reactivex.rxkotlin.subscribeBy import io.reactivex.schedulers.Schedulers import io.reactivex.subjects.PublishSubject +import org.koin.android.ext.android.inject import kotlin.math.roundToInt class ReadingActivity : AppCompatActivity() { @@ -46,6 +47,8 @@ class ReadingActivity : AppCompatActivity() { UNKNOWN(GoogleMaterial.Icon.gmd_battery_unknown) } + private val genericInfo by inject<GenericInfo>() + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -56,7 +59,7 @@ class ReadingActivity : AppCompatActivity() { batterySetup() intent.getStringExtra("model") - ?.fromJson<ChapterModel>(ChapterModel::class.java to ChapterModelDeserializer(BaseMainActivity.genericInfo)) + ?.fromJson<ChapterModel>(ChapterModel::class.java to ChapterModelDeserializer(genericInfo)) ?.getChapterInfo() ?.subscribeOn(Schedulers.io()) ?.observeOn(AndroidSchedulers.mainThread())